Merge pull request #27 from Day8/feature/filter-events
Feature/filter events
This commit is contained in:
commit
9eae81a000
|
@ -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"}]])
|
|
@ -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;
|
||||
}
|
||||
")
|
|
@ -1,5 +1,7 @@
|
|||
(ns day8.re-frame.trace
|
||||
(: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]
|
||||
[cljs.pprint :as pprint]
|
||||
[clojure.string :as str]
|
||||
|
@ -12,8 +14,8 @@
|
|||
[goog.object :as gob]
|
||||
[re-frame.interop :as interop]
|
||||
|
||||
[devtools.formatters.core :as devtools]
|
||||
))
|
||||
[devtools.formatters.core :as devtools]))
|
||||
|
||||
|
||||
(defn comp-name [c]
|
||||
(let [n (or (component/component-path c)
|
||||
|
@ -61,9 +63,9 @@
|
|||
(trace/with-trace {:op-type :render
|
||||
:tags {:component-path (reagent.impl.component/component-path c)}
|
||||
:operation (last (str/split name #" > "))}
|
||||
(real-renderer c)
|
||||
(real-renderer c)))))
|
||||
|
||||
|
||||
))))
|
||||
|
||||
(set! reagent.impl.component/static-fns static-fns)
|
||||
|
||||
|
@ -88,8 +90,8 @@
|
|||
#_(set! reagent.impl.batching/schedule schedule
|
||||
#_(fn []
|
||||
(reagent.impl.batching/do-after-render (fn [] (trace/with-trace {:op-type :raf-end})))
|
||||
(real-schedule)))
|
||||
))
|
||||
(real-schedule)))))
|
||||
|
||||
|
||||
(def traces (interop/ratom []))
|
||||
(defn log-trace? [trace]
|
||||
|
@ -113,80 +115,124 @@
|
|||
(defn init-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)
|
||||
save #(let [v (-> @val str clojure.string/trim)]
|
||||
(on-save v))]
|
||||
save #(let [v (-> @val str str/trim)]
|
||||
(when (pos? (count v))
|
||||
(on-save v)))]
|
||||
(fn []
|
||||
[:input {:type "text"
|
||||
[:input {:style {:margin-left 7}
|
||||
:type "text"
|
||||
:value @val
|
||||
:auto-focus true
|
||||
:on-blur save
|
||||
:on-change #(reset! val (-> % .-target .-value))
|
||||
:on-change #(do (reset! val (-> % .-target .-value))
|
||||
(on-change %))
|
||||
:on-key-down #(case (.-which %)
|
||||
13 (save)
|
||||
13 (do
|
||||
(save)
|
||||
(reset! val ""))
|
||||
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 []
|
||||
(let [search (r/atom "")
|
||||
slower-than-ms (r/atom "")
|
||||
slower-than-bold (r/atom "")]
|
||||
(fn []
|
||||
(let [slower-than-ms-int (js/parseInt @slower-than-ms)
|
||||
slower-than-bold-int (js/parseInt @slower-than-bold)
|
||||
op-filter (when-not (str/blank? @search)
|
||||
(filter #(str/includes? (str (:operation %) " " (:op-type %)) @search)))
|
||||
ms-filter (when-not (str/blank? @slower-than-ms)
|
||||
(filter #(< slower-than-ms-int (:duration %))))
|
||||
transducers (apply comp (remove nil? [ms-filter op-filter]))
|
||||
showing-traces (sequence transducers @traces)
|
||||
|
||||
filter-msg (if (and (str/blank? @search) (str/blank? @slower-than-ms))
|
||||
(str "Filter " (count @traces) " events: ")
|
||||
(str "Filtering " (count showing-traces) " of " (count @traces) " events:"))
|
||||
padding {:padding "0px 5px 0px 5px"}]
|
||||
[:div
|
||||
{:style {:padding "10px"}}
|
||||
[:h1 "TRACES"]
|
||||
[:span filter-msg [:button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} " Clear traces"]] [:br]
|
||||
[:span "Filter events " [search-input {:on-save #(reset! search %)}]] [:br]
|
||||
[:span "Filter slower than " [search-input {:on-save #(reset! slower-than-ms %)}] "ms "] [:br]
|
||||
[:span "Bold slower than " [search-input {:on-save #(reset! slower-than-bold %)}] "ms "]
|
||||
[:table
|
||||
{:cell-spacing "0" :width "100%"}
|
||||
[:thead>tr
|
||||
[:th "op"]
|
||||
[:th "event"]
|
||||
[:th "meta"]]
|
||||
[:tbody
|
||||
(defn 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))
|
||||
]
|
||||
(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 "red"
|
||||
:sub/run "#fd701e"
|
||||
:event "blue"
|
||||
:render "purple"
|
||||
:re-frame.router/fsm-trigger "red"
|
||||
: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"
|
||||
"")})}
|
||||
{: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)))]])
|
||||
))))]]]))))
|
||||
[: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 []
|
||||
(let [showing-traces (if (= @filter-items [])
|
||||
@traces
|
||||
(filter (apply every-pred (map query->fn @filter-items)) @traces))
|
||||
save-query (fn [_]
|
||||
(if (and (= @filter-type :slower-than)
|
||||
(js/isNaN (js/parseFloat @filter-input)))
|
||||
(reset! input-error true)
|
||||
(do
|
||||
(reset! input-error false)
|
||||
(swap! filter-items conj {:id (random-uuid)
|
||||
:query (if (= @filter-type :contains)
|
||||
(str/lower-case @filter-input)
|
||||
(js/parseFloat @filter-input))
|
||||
:filter-type @filter-type}))))]
|
||||
[:div
|
||||
[:div.filter-control {:style {:margin-bottom 20}}
|
||||
[:div.filter-control-input
|
||||
{:style {:margin-bottom 10}}
|
||||
[:select {:value @filter-type
|
||||
:on-change #(reset! filter-type (keyword (.. % -target -value)))}
|
||||
[: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
|
||||
{:cell-spacing "0" :width "100%"}
|
||||
[:thead>tr
|
||||
[:th "operations"]
|
||||
[: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"]]
|
||||
[:tbody (render-traces showing-traces)]]]))))
|
||||
|
||||
(defn resizer-style [draggable-area]
|
||||
{:position "absolute" :z-index 2 :opacity 0
|
||||
|
@ -198,7 +244,7 @@
|
|||
;; Add clear button
|
||||
;; Filter out different trace types
|
||||
(let [position (r/atom :right)
|
||||
size (r/atom 0.3)
|
||||
size (r/atom 0.35)
|
||||
showing? (r/atom false)
|
||||
dragging? (r/atom false)
|
||||
pin-to-bottom? (r/atom true)
|
||||
|
@ -229,11 +275,13 @@
|
|||
transition (if @showing?
|
||||
ease-transition
|
||||
(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 {:style {:position "fixed" :z-index 1 :box-shadow "rgba(0, 0, 0, 0.298039) 0px 0px 4px" :background "white"
|
||||
[:div.panel-wrapper
|
||||
{:style {:position "fixed" :width "0px" :height "0px" :top "0px" :left "0px" :z-index 99999999}}
|
||||
[:div.panel
|
||||
{:style {:position "fixed" :z-index 1 :box-shadow "rgba(0, 0, 0, 0.298039) 0px 0px 4px" :background "white"
|
||||
:left left :top "0px" :width (str (* 100 @size) "%") :height "100%"
|
||||
:transition transition}}
|
||||
[:div.resizer {:style (resizer-style draggable-area)
|
||||
[:div.panel-resizer {:style (resizer-style draggable-area)
|
||||
:on-mouse-down #(reset! dragging? true)
|
||||
:on-mouse-up #(reset! dragging? false)
|
||||
:on-mouse-move (fn [e]
|
||||
|
@ -243,13 +291,19 @@
|
|||
(.preventDefault e)
|
||||
(reset! size (/ (- full-width x)
|
||||
full-width)))))}]
|
||||
[:div {:style {:width "100%" :height "100%" :overflow "auto"}}
|
||||
[:button {:on-click #(reset! selected-tab :traces)} "Traces"]
|
||||
[:button {:on-click #(reset! selected-tab :subvis)} "SubVis"]
|
||||
[: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 #(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-traces]
|
||||
:traces [render-trace-panel]
|
||||
:subvis [subvis/render-subvis traces]
|
||||
[render-traces])]]]))})))
|
||||
[render-trace-panel])]]]]))})))
|
||||
|
||||
(defn panel-div []
|
||||
(let [id "--re-frame-trace--"
|
||||
|
@ -259,7 +313,26 @@
|
|||
(let [new-panel (.createElement js/document "div")]
|
||||
(.setAttribute new-panel "id" id)
|
||||
(.appendChild (.-body js/document) new-panel)
|
||||
(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)))
|
||||
|
|
|
@ -43,8 +43,6 @@
|
|||
simulation-a (atom nil)]
|
||||
(fn []
|
||||
[:div
|
||||
{:style {:padding "10px"}}
|
||||
[:h1 "SUBVIS"]
|
||||
[d3t/create-d3
|
||||
{:render-component (fn [ratom]
|
||||
[:svg#d3cmp {:width width :height height}])
|
||||
|
@ -184,9 +182,8 @@
|
|||
|
||||
(.. simulation
|
||||
(restart)
|
||||
(alpha 0.3)))))
|
||||
]
|
||||
))))}
|
||||
(alpha 0.3)))))]))))}
|
||||
|
||||
|
||||
traces-ratom]
|
||||
[:hr]])))
|
||||
|
||||
|
|
Loading…
Reference in New Issue