<commit_before>(ns metlog-client.metlog
  (:require-macros [cljs.core.async.macros :refer [ go ]]
                   [metlog-client.macros :refer [ watch ]])
  (:require [reagent.core :as reagent :refer [atom]]
            [ajax.core :refer [GET]]
            [cljs.reader :as reader]
            [cljs.core.async :refer [put! close! chan <!]]
            [metlog-client.tsplot :as tsplot]))

(defonce query-window-secs (atom (* 3600 24)))

(def dashboard-state (atom {:series [] :text ""}))

(def window-width (atom 1024))

(defn <<< [f & args]
  (let [c (chan)]
    (apply f (concat args [(fn [x]
                             (if (or (nil? x)
                                     (undefined? x))
                                   (close! c)
                                   (put! c x)))]))
    c))

(defn ajax-get [ url callback ]
  (GET url {:handler callback
            :error-handler (fn [ resp ]
                             (.log js/console (str "HTTP error, url: " url " resp: " resp)))}))

(defn fetch-series-names [ cb ]
  (ajax-get "/series-names" cb))

(defn fetch-latest-series-data [ series-name cb ]
  (ajax-get (str "/latest/" series-name) cb))

(defn fetch-series-data [ series-name query-window-secs cb ]
  (ajax-get (str "/data/" series-name "?query-window-secs=" query-window-secs)
            (fn [ data ]
              (cb data))))

(defn tsplot-fetch-and-draw [ canvas series-name width ]
  (let [ ctx (.getContext canvas "2d")]
    (go
      (tsplot/draw ctx width 180  (<! (<<< fetch-series-data
                                           series-name
                                           @query-window-secs))))))

(defn dom-width [ node ]
  (if node
    (.-clientWidth node)
    1024))

(defn series-tsplot [ series ]
  (let [ series-state (atom { }) ]
    (reagent/create-class
     {:display-name (str "series-tsplot-" (:name series))
      :component-did-update
      (fn [ this ]
        (tsplot-fetch-and-draw (reagent/dom-node this) (:name series) (dom-width (:dom-node @series-state))))
      
      :component-did-mount
      (fn [ this ]
        (swap! series-state assoc :dom-node (.-parentNode (reagent/dom-node this)))        
        (tsplot-fetch-and-draw (reagent/dom-node this) (:name series) (dom-width (.-parentNode (reagent/dom-node this)))))

      :reagent-render
      (fn [ ]
        @window-width
        [:canvas { :width (dom-width (:dom-node @series-state)) :height 180}])})))

(defn series-pane [ series ]
  [:div.series-pane
   [:div.series-pane-header
    [:span.series-name (:name series)]]
   [series-tsplot series]])

(defn series-list [ ]
  [:div
   (for [ series (:series @dashboard-state)]
     ^{ :key (:name series) } [series-pane series])])

(defn end-edit [ text state ]
  (let [ qws (js/parseInt text) ]
    (reset! query-window-secs qws)))

(defn input-field [ on-enter ]
  (let [ state (atom { :text "" }) ]
    (fn []
      [:input {:value (:text @state)
               :onChange #(swap! state assoc :text (.. % -target -value))
               :onKeyDown #(do
                             (when (= (.-key %) "Enter")
                                 (on-enter (:text @state))))} ])))
<commit_msg>Decouple plot drawing from plot fetching.<commit_after>(ns metlog-client.metlog
  (:require-macros [cljs.core.async.macros :refer [ go ]]
                   [metlog-client.macros :refer [ watch ]])
  (:require [reagent.core :as reagent :refer [atom]]
            [ajax.core :refer [GET]]
            [cljs.reader :as reader]
            [cljs.core.async :refer [put! close! chan <!]]
            [metlog-client.tsplot :as tsplot]))

(defonce query-window-secs (atom (* 3600 24)))

(def dashboard-state (atom {:series [] :text ""}))

(def window-width (atom 1024))

(defn <<< [f & args]
  (let [c (chan)]
    (apply f (concat args [(fn [x]
                             (if (or (nil? x)
                                     (undefined? x))
                                   (close! c)
                                   (put! c x)))]))
    c))

(defn ajax-get [ url callback ]
  (GET url {:handler callback
            :error-handler (fn [ resp ]
                             (.log js/console (str "HTTP error, url: " url " resp: " resp)))}))

(defn fetch-series-names [ cb ]
  (ajax-get "/series-names" cb))

(defn fetch-latest-series-data [ series-name cb ]
  (ajax-get (str "/latest/" series-name) cb))

(defn fetch-series-data [ series-name query-window-secs cb ]
  (ajax-get (str "/data/" series-name "?query-window-secs=" query-window-secs)
            (fn [ data ]
              (cb data))))

(defn tsplot-draw [ canvas width series-data ]
  (let [ ctx (.getContext canvas "2d")]
    (tsplot/draw ctx width 180 series-data)))

(defn tsplot-fetch-and-draw [ canvas width series-name ]
  (go
    (tsplot-draw canvas width
                 (<! (<<< fetch-series-data series-name @query-window-secs)))))

(defn dom-width [ node ]
  (if node
    (.-clientWidth node)
    1024))

(defn series-tsplot [ series ]
  (let [ series-state (atom { }) ]
    (reagent/create-class
     {:display-name (str "series-tsplot-" (:name series))
      :component-did-update
      (fn [ this ]
        (watch :component-did-update)
        (tsplot-draw (reagent/dom-node this) (dom-width (:dom-node @series-state)) (:series-data @series-state)))
      
      :component-did-mount
      (fn [ this ]
        (watch :component-did-mount)
        (swap! series-state assoc :dom-node (.-parentNode (reagent/dom-node this)))
        (go
          (swap! series-state assoc :series-data (<! (<<< fetch-series-data (:name series) @query-window-secs)))))

      :reagent-render
      (fn [ ]
        @window-width
        (watch :reagent-render)
        [:canvas { :width (dom-width (:dom-node @series-state)) :height 180}])})))

(defn series-pane [ series ]
  [:div.series-pane
   [:div.series-pane-header
    [:span.series-name (:name series)]]
   [series-tsplot series]])

(defn series-list [ ]
  [:div
   (for [ series (:series @dashboard-state) ]
     ^{ :key (:name series) } [series-pane series])])

(defn end-edit [ text state ]
  (let [ qws (js/parseInt text) ]
    (reset! query-window-secs qws)))

(defn input-field [ on-enter ]
  (let [ state (atom { :text "" }) ]
    (fn []
      [:input {:value (:text @state)
               :onChange #(swap! state assoc :text (.. % -target -value))
               :onKeyDown #(do
                             (when (= (.-key %) "Enter")
                                 (on-enter (:text @state))))} ])))

{'fraction_non_alphanumeric': 0.1688191881918819, 'fraction_numerical': 0.006457564575645757, 'mean_word_length': 1.9635535307517085, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6017', 'n_tokens_mistral': 2205, 'n_tokens_neox': 2112, 'n_words': 530}