<commit_before>(ns pepa.workflows.dashboard
  (:require [om.core :as om :include-macros true]
            [nom.ui :as ui]

            [cljs.reader :as reader]
            [cljs.core.async :as async]
            [clojure.string :as s]

            [pepa.api :as api]
            [pepa.data :as data]
            [pepa.search :as search]
            [pepa.navigation :as nav]
            [pepa.style :as css]
            [pepa.selection :as selection]

            [pepa.components.page :as page]
            [pepa.components.tags :as tags]
            [pepa.components.draggable :as draggable])
  (:require-macros [cljs.core.async.macros :refer [go go-loop]]
                   [cljs.core.match.macros :refer [match]]))

(defn ^:private handle-tags-drop [document e]
  (when-let [tags (tags/data-transfer-tags e.dataTransfer)]
    (api/update-document! (update-in document [:tags]
                                     #(data/add-tags % tags)))
    (.preventDefault e)))

(ui/defcomponent ^:private page-count [pages]
  (render [_]
    [:.page-count (count pages)]))

(defn ^:private document-click [click-type document owner e]
  {:pre [(contains? #{:single :double} click-type)]}
  (when-let [clicks (om/get-state owner :clicks)]
    (async/put! clicks (assoc (selection/event->click (:id document) e)
                              ::type click-type)))
  (ui/cancel-event e))

(ui/defcomponent ^:private document-preview [document owner]
  (render [_]
    (let [href (nav/document-route document)]
      ;; NOTE: We can't wrap the <a> around all those divs. It's
      ;; forbidden to put a <div> inside <a> if there are other
      ;; <a>s and other stuff inside it. If we try it nonetheless,
      ;; the browser will reorder or DOM and React will fail
      ;; horribly.
      [:.document {:on-drag-over tags/accept-tags-drop
                   :on-drop (partial handle-tags-drop document)
                   :on-click (partial document-click :single document owner)
                   :on-double-click (partial document-click :double document owner)
                   :class [(when (::selected document) "selected")]}
       [:.preview {:key "preview"}
        [:a {:href href}
         (om/build page/thumbnail (-> document :pages first) {:key :id})
         (om/build page-count (:pages document)
                   {:react-key "page-count"})]]
       [:a.title {:href href, :key "a.title"}
        (:title document)]
       (om/build tags/tags-list (:tags document)
                 {:react-key "tags-list"})])))

(ui/defcomponent ^:private sidebar-pane [state owner _]
  (render [_]
    (let [sidebar-width (get (om/observe owner (data/ui-sidebars)) ::sidebar
                             css/default-sidebar-width)]
      [:.pane {:key "sidebar-pane"
               :style {:min-width sidebar-width :max-width sidebar-width}}
       [:.sidebar
        [:header "Sorting & Filtering"]
        (om/build draggable/resize-draggable nil {:opts {:sidebar ::sidebar}})]])))

(defn ^:private document-ids [state]
  (:results (search/current-search state)))

(def +initial-elements+ 50)
(def +to-load+ 50)

(defn ^:private parse-query-number [state name & [default]]
  (or
   (try
     (let [n (some-> (get-in state [:navigation :query-params name])
                     (js/parseInt 10))]
       (and (integer? n) n))
     (catch js/Error e nil))
   default
   0))

(defn ^:private parse-count-scroll
  [state]
  [(parse-query-number state :count +initial-elements+)
   (parse-query-number state :scroll 0)])

(defn ^:private page-ids [state]
  (let [[n _] (parse-count-scroll state)]
    (take n (document-ids state))))

(defn ^:private fetch-missing-documents!
  "Fetches all missing documents which will be visible in the
  documents-overview."
  [state owner]
  (go
    (let [ids (page-ids state)
          missing (remove (set (keys (:documents state))) ids)]
      (when (seq missing)
        (println "fetching missing documents:" missing)
        (<! (api/fetch-documents! missing))))))

(ui/defcomponent ^:private document-count [document-ids]
  (render [_]
    [:span.document-count
     (str "(" (count document-ids) ")")]))

(ui/defcomponent ^:private dashboard-title [search owner opts]
  (render [_]
    (let [documents (:results search)
          active-search? (search/search-active? search)]
      [:span
       (cond
         active-search?
         "Loading..."

         (search/all-documents? search)
         "All Documents"

         (:query search)
         "Search Results"

         true
         "Dashboard")
       (when-not active-search?
        (om/build document-count documents
                  {:react-key "document-count"}))])))

;;; Should be twice the document-height or so.
(def +scroll-margin+ 500)

(defn ^:private on-documents-scroll [state owner e]
  (let [container e.currentTarget
        scroll-top (.-scrollTop container)
        scroll-height (.-scrollHeight container)<commit_msg>Indent fix.<commit_after>(ns pepa.workflows.dashboard
  (:require [om.core :as om :include-macros true]
            [nom.ui :as ui]

            [cljs.reader :as reader]
            [cljs.core.async :as async]
            [clojure.string :as s]

            [pepa.api :as api]
            [pepa.data :as data]
            [pepa.search :as search]
            [pepa.navigation :as nav]
            [pepa.style :as css]
            [pepa.selection :as selection]

            [pepa.components.page :as page]
            [pepa.components.tags :as tags]
            [pepa.components.draggable :as draggable])
  (:require-macros [cljs.core.async.macros :refer [go go-loop]]
                   [cljs.core.match.macros :refer [match]]))

(defn ^:private handle-tags-drop [document e]
  (when-let [tags (tags/data-transfer-tags e.dataTransfer)]
    (api/update-document! (update-in document [:tags]
                                     #(data/add-tags % tags)))
    (.preventDefault e)))

(ui/defcomponent ^:private page-count [pages]
  (render [_]
    [:.page-count (count pages)]))

(defn ^:private document-click [click-type document owner e]
  {:pre [(contains? #{:single :double} click-type)]}
  (when-let [clicks (om/get-state owner :clicks)]
    (async/put! clicks (assoc (selection/event->click (:id document) e)
                              ::type click-type)))
  (ui/cancel-event e))

(ui/defcomponent ^:private document-preview [document owner]
  (render [_]
    (let [href (nav/document-route document)]
      ;; NOTE: We can't wrap the <a> around all those divs. It's
      ;; forbidden to put a <div> inside <a> if there are other
      ;; <a>s and other stuff inside it. If we try it nonetheless,
      ;; the browser will reorder or DOM and React will fail
      ;; horribly.
      [:.document {:on-drag-over tags/accept-tags-drop
                   :on-drop (partial handle-tags-drop document)
                   :on-click (partial document-click :single document owner)
                   :on-double-click (partial document-click :double document owner)
                   :class [(when (::selected document) "selected")]}
       [:.preview {:key "preview"}
        [:a {:href href}
         (om/build page/thumbnail (-> document :pages first) {:key :id})
         (om/build page-count (:pages document)
                   {:react-key "page-count"})]]
       [:a.title {:href href, :key "a.title"}
        (:title document)]
       (om/build tags/tags-list (:tags document)
                 {:react-key "tags-list"})])))

(ui/defcomponent ^:private sidebar-pane [state owner _]
  (render [_]
    (let [sidebar-width (get (om/observe owner (data/ui-sidebars)) ::sidebar
                             css/default-sidebar-width)]
      [:.pane {:key "sidebar-pane"
               :style {:min-width sidebar-width :max-width sidebar-width}}
       [:.sidebar
        [:header "Sorting & Filtering"]
        (om/build draggable/resize-draggable nil {:opts {:sidebar ::sidebar}})]])))

(defn ^:private document-ids [state]
  (:results (search/current-search state)))

(def +initial-elements+ 50)
(def +to-load+ 50)

(defn ^:private parse-query-number [state name & [default]]
  (or
   (try
     (let [n (some-> (get-in state [:navigation :query-params name])
                     (js/parseInt 10))]
       (and (integer? n) n))
     (catch js/Error e nil))
   default
   0))

(defn ^:private parse-count-scroll
  [state]
  [(parse-query-number state :count +initial-elements+)
   (parse-query-number state :scroll 0)])

(defn ^:private page-ids [state]
  (let [[n _] (parse-count-scroll state)]
    (take n (document-ids state))))

(defn ^:private fetch-missing-documents!
  "Fetches all missing documents which will be visible in the
  documents-overview."
  [state owner]
  (go
    (let [ids (page-ids state)
          missing (remove (set (keys (:documents state))) ids)]
      (when (seq missing)
        (println "fetching missing documents:" missing)
        (<! (api/fetch-documents! missing))))))

(ui/defcomponent ^:private document-count [document-ids]
  (render [_]
    [:span.document-count
     (str "(" (count document-ids) ")")]))

(ui/defcomponent ^:private dashboard-title [search owner opts]
  (render [_]
    (let [documents (:results search)
          active-search? (search/search-active? search)]
      [:span
       (cond
         active-search?
         "Loading..."

         (search/all-documents? search)
         "All Documents"

         (:query search)
         "Search Results"

         true
         "Dashboard")
       (when-not active-search?
         (om/build document-count documents
                   {:react-key "document-count"}))])))

;;; Should be twice the document-height or so.
(def +scroll-margin+ 500)

(defn ^:private on-documents-scroll [state owner e]
  (let [container e.currentTarget
        scroll-top (.-scrollTop container)
        scroll-height (.-scrollHeight container)
{'fraction_non_alphanumeric': 0.1466653152240016, 'fraction_numerical': 0.0022298803973241437, 'mean_word_length': 2.348150661689854, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3504644', 'n_tokens_mistral': 3153, 'n_tokens_neox': 2987, 'n_words': 844}