Browse Source

DB helpers

Tienson Qin 5 years ago
parent
commit
65dce77d65

+ 37 - 28
frontend/src/frontend/components/file.cljs

@@ -1,33 +1,42 @@
 (ns frontend.components.file
-  ;; (:require [rum.core :as rum]
-  ;;           [frontend.mui :as mui]
-  ;;           ["@material-ui/core/colors" :as colors]
-  ;;           [frontend.state :as state]
-  ;;           [frontend.util :as util]
-  ;;           [frontend.handler :as handler]
-  ;;           [clojure.string :as string])
-  )
+  (:require [rum.core :as rum]
+            [frontend.util :as util]
+            [frontend.handler :as handler]
+            [clojure.string :as string]
+            [frontend.db :as db]
+            [frontend.components.sidebar :as sidebar]
+            [frontend.format :as format]
+            [goog.crypt.base64 :as b64]))
 
-;; (rum/defc files-list
-;;   [current-repo files]
-;;   [:div
-;;    (if (seq files)
-;;      (let [files-set (set files)
-;;            prefix [(files-set "tasks.org")]
-;;            files (->> (remove (set prefix) files)
-;;                       (concat prefix)
-;;                       (remove nil?))]
-;;        (mui/list
-;;         (for [file files]
-;;           (mui/list-item
-;;            {:button true
-;;             :key file
-;;             :style {:overflow "hidden"}
-;;             :on-click (fn []
-;;                         (handler/load-file current-repo file)
-;;                         (handler/toggle-drawer? false))}
-;;            (mui/list-item-text file)))))
-;;      "Loading...")])
+(defn- get-path
+  [state]
+  (let [route-match (first (:rum/args state))]
+    (->> (get-in route-match [:parameters :path :path])
+         (b64/decodeString))))
+
+(rum/defq file <
+  {:q (fn [state]
+        (db/sub-file (get-path state)))
+   :did-mount (fn [state]
+                (doseq [block (-> (js/document.querySelectorAll "pre code")
+                                  (array-seq))]
+                  (js/hljs.highlightBlock block))
+                state)}
+  [state content]
+  (let [path (get-path state)
+        content (ffirst content)
+        suffix (last (string/split path #"\."))]
+    (sidebar/sidebar
+     (if (and suffix (contains? #{"md" "markdown" "org"} suffix))
+       [:div.flex.justify-center
+        [:div.m-6.flex-1 {:style {:max-width 900}}
+         [:a {:style {:float "right"}
+              :href "/edit"}
+          "edit"]
+         (if content
+           (util/raw-html (format/to-html content suffix))
+           "Loading ...")]]
+       [:div "File " suffix " is not supported."]))))
 
 ;; (rum/defc edit < rum/reactive
 ;;   []

+ 2 - 93
frontend/src/frontend/components/home.cljs

@@ -6,21 +6,11 @@
             [frontend.mixins :as mixins]
             [frontend.config :as config]
             [rum.core :as rum]
-            ;; [frontend.components.agenda :as agenda]
-            ;; [frontend.components.file :as file]
-            ;; [frontend.components.settings :as settings]
-            ;; [frontend.components.repo :as repo]
             [frontend.format :as format]
             [clojure.string :as string]
             [frontend.db :as db]
             [frontend.components.sidebar :as sidebar]))
 
-;; (rum/defq query-test <
-;;   {:q (fn []
-;;         (db/pull '[*] [:db/ident :settings]))}
-;;   [state query-result]
-;;   [:div (:github-token query-result)])
-
 (rum/defc front-page
   []
   [:div.relative.min-h-screen.overflow-hidden.bg-gray-900.lg:bg-gray-300
@@ -81,89 +71,8 @@
          "Author of Refactoring UI"]]]]]]])
 
 (rum/defq home <
-  {:q (fn [] (db/sub-github-token))}
+  {:q (fn [_state] (db/sub-github-token))}
   [state {:keys [:github/token]}]
   (if token
-    (sidebar/sidebar)
+    (sidebar/sidebar (sidebar/main-content))
     (front-page)))
-
-;; (rum/defc content-html
-;;   < {:did-mount (fn [state]
-;;                   (doseq [block (-> (js/document.querySelectorAll "pre code")
-;;                                     (array-seq))]
-;;                     (js/hljs.highlightBlock block))
-;;                   state)}
-;;   [current-file html-content]
-;;   [:div
-;;    (mui/link {:style {:float "right"}
-;;               :on-click (fn []
-;;                           (handler/change-page :edit-file))}
-;;      "edit")
-;;    (util/raw-html html-content)])
-
-;; (rum/defc home < rum/reactive
-;;   []
-;;   (let [state (rum/react state/state)
-;;         {:keys [user tokens repos repo-url github-token github-repo contents loadings current-repo current-file width drawer? tasks cloning?]} state
-;;         current-repo (or current-repo
-;;                          (when-let [first-repo (first (keys repos))]
-;;                            (handler/set-current-repo first-repo)
-;;                            first-repo))
-;;         files (get-in state [:repos current-repo :files])
-;;         cloned? (get-in state [:repos current-repo :cloned?])
-;;         loading? (get loadings current-file)
-;;         width (or width (util/get-width))
-;;         mobile? (and width (<= width 600))]
-;;     (prn {:current-repo current-repo
-;;           :cloned? cloned?})
-;;     (mui/container
-;;      {:id "root-container"
-;;       :style {:display "flex"
-;;               :justify-content "center"
-;;               ;; TODO: fewer spacing for mobile, 24px
-;;               :margin-top 64}}
-;;      (cond
-;;        (nil? user)
-;;        (mui/button {:variant "contained"
-;;                     :color "primary"
-;;                     :start-icon (mui/github-icon)
-;;                     :href "/login/github"}
-;;          "Login with Github")
-
-;;        (empty? repos)
-;;        (repo/add-repo repo-url)
-
-;;        cloned?
-;;        (mui/grid
-;;         {:container true
-;;          :spacing 3}
-;;         (when-not mobile?
-;;           (mui/grid {:xs 2}
-;;                     (file/files-list current-repo files)))
-
-;;         (if (and (not mobile?)
-;;                  (not drawer?))
-;;           (mui/divider {:orientation "vertical"
-;;                         :style {:margin "0 24px"}}))
-;;         (mui/grid {:xs 9
-;;                    :style {:margin-left (if (or mobile? drawer?) 24 0)}}
-;;                   (cond
-;;                     (nil? current-file)
-;;                     (agenda/agenda tasks)
-
-;;                     loading?
-;;                     [:div "Loading ..."]
-
-;;                     :else
-;;                     (let [content (get contents current-file)
-;;                           suffix (last (string/split current-file #"\."))]
-;;                       (if (and suffix (contains? #{"md" "markdown" "org"} suffix))
-;;                         (content-html current-file (format/to-html content suffix))
-;;                         [:div "File " suffix " is not supported."])))))
-;;        cloning?
-;;        [:div "Cloning..."]
-
-;;        :else
-;;        [:div "TBC"]
-;;        ;; (settings/settings-form github-token github-repo)
-;;        ))))

+ 3 - 2
frontend/src/frontend/components/repo.cljs

@@ -19,7 +19,7 @@
                                 )}
            (string/replace url "https://github.com/" "")]])]])))
 
-(rum/defcs add-repo < (rum/local "" ::repo-url)
+(rum/defcs add-repo < (rum/local "https://github.com/" ::repo-url)
   [state]
   (let [repo-url (get state ::repo-url)]
     [:div.p-8.flex.items-center.justify-center.bg-white
@@ -30,7 +30,8 @@
         "Repo"]
        [:div.mt-1.relative.rounded-md.shadow-sm
         [:input.form-input.block.w-full.sm:text-sm.sm:leading-5
-         {:placeholder "https://github.com/yourname/repo"
+         {:auto-focus true
+          :placeholder "https://github.com/yourname/repo"
           :value @repo-url
           :on-change (fn [e]
                        (reset! repo-url (util/evalue e)))}]]]

+ 31 - 10
frontend/src/frontend/components/sidebar.cljs

@@ -3,7 +3,10 @@
             [frontend.ui :as ui]
             [frontend.mixins :as mixins]
             [frontend.db :as db]
-            [frontend.components.repo :as repo]))
+            [frontend.components.repo :as repo]
+            [goog.crypt.base64 :as b64]
+            [frontend.util :as util]
+            ))
 
 (defonce active-button :a.group.flex.items-center.px-2.py-2.text-base.leading-6.font-medium.rounded-md.text-white.bg-gray-900.focus:outline-none.focus:bg-gray-700.transition.ease-in-out.duration-150)
 (defonce inactive-button :a.mt-1.group.flex.items-center.px-2.py-2.text-base.leading-6.font-medium.rounded-md.text-gray-300.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150)
@@ -23,22 +26,38 @@
          :stroke-linecap "round"}]]
       title])))
 
+(rum/defq files-list <
+  {:q (fn [] (db/sub-files))}
+  [state files]
+  [:div.cursor-pointer.my-1.flex.flex-col.ml-2
+   (if (seq files)
+     (let [files (->> files (map first))]
+       (prn files)
+       (for [file files]
+         [:a {:key file
+              :class (util/hiccup->class "mt-1.group.flex.items-center.px-2.py-1.text-base.leading-6.font-medium.rounded-md.text-gray-500.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150")
+              :href (str "/file/" (b64/encodeString file))}
+          file])))])
+
 (rum/defc sidebar-nav
   []
   [:nav.flex-1.px-2.py-4.bg-gray-800
-   (nav-item "Agenda" "#"
-             "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
+   (nav-item "Daily notes" "#"
+             "M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10M9 21h6"
              true)
-   (nav-item "Journal" "#"
-             "M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10M9 21h6")
+   (nav-item "Agenda" "#"
+             "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z")
+   (nav-item "Budgets" "#"
+             "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z")
    (nav-item "Files" "#"
              "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z")
+
+   (files-list)
    ])
 
 (rum/defq main-content <
-  {:q (fn [] (db/sub-repos))}
+  {:q (fn [_state] (db/sub-repos))}
   [state repos]
-  (prn {:repos repos})
   [:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
    (if (seq repos)
      [:div
@@ -46,7 +65,7 @@
      (repo/add-repo))])
 
 (rum/defcs sidebar < (mixins/modal)
-  [state]
+  [state main-content]
   (let [{:keys [open? close-fn open-fn]} state]
     [:div.h-screen.flex.overflow-hidden.bg-gray-100
      [:div.md:hidden
@@ -131,7 +150,9 @@
       [:main.flex-1.relative.z-0.overflow-y-auto.py-6.focus:outline-none
        ;; {:x-init "$el.focus()", :x-data "x-data", :tabindex "0"}
        {:tabIndex "0"}
-       (main-content)
+       main-content
        [:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
         [:div.py-4
-         [:div.border-4.border-dashed.border-gray-200.rounded-lg.h-96]]]]]]))
+         [:div.border-4.border-dashed.border-gray-200.rounded-lg.h-96]]]
+       ]
+      ]]))

+ 89 - 16
frontend/src/frontend/db.cljs

@@ -13,6 +13,7 @@
    :repo/url        {:db/unique :db.unique/identity}
    :repo/cloning?   {}
    :repo/cloned?    {}
+   :repo/current    {:db/valueType   :db.type/ref}
 
    ;; file
    :file/path       {:db/unique :db.unique/identity}
@@ -186,32 +187,60 @@
   [tx-data]
   (posh/transact! conn tx-data))
 
+(defn set-key-value
+  [key value]
+  (transact! [{:db/id -1
+               :db/ident key
+               key value}]))
+
 (defn transact-github-token!
   [token]
-  (when token
-    (transact! [{:db/id -1
-                 :db/ident :github/token
-                 :github/token token}])))
+  (set-key-value :github/token token))
 
 (defn get-key-value
   [key]
   (some-> (d/entity (d/db conn) key)
-      key))
+          key))
 
 (defn sub-github-token
   []
-  (pull '[*] :github/token))
+  (pull '[*] [:db/ident :github/token]))
 
 (defn get-github-token
   []
   (get-key-value :github/token))
 
+(defn set-current-repo!
+  [repo]
+  (set-key-value :repo/current [:repo/url repo]))
+
+(defn sub-current-repo
+  []
+  (pull '[*] [:db/ident :repo/current]))
+
 (defn sub-repos
   []
   (q '[:find ?url
        :where [_ :repo/url ?url]]
     conn))
 
+(defn get-repos
+  []
+  (->> (d/q '[:find ?url
+              :where [_ :repo/url ?url]]
+         @conn)
+       (map first)
+       distinct))
+
+(defn sub-files
+  []
+  (q '[:find ?path
+       :where
+       [_     :repo/current ?repo]
+       [?file :file/repo ?repo]
+       [?file :file/path ?path]]
+    conn))
+
 (defn set-repo-cloning
   [repo-url value]
   (d/transact! conn
@@ -229,22 +258,66 @@
   [repo-url files]
   (d/transact! conn
     (for [file files]
-     {:file/repo [:db/ident repo-url]
-      :file/path file})))
+      {:file/repo [:repo/url repo-url]
+       :file/path file})))
 
-(defn get-files
-  []
-  (->> (d/q '[:find ?file
-              :where [_ :repo/path ?file]]
-         conn)
+(defn get-repo-files
+  [repo-url]
+  (->> (d/q '[:find ?path
+              :in $ ?repo-url
+              :where
+              [?repo :repo/url ?repo-url]
+              [?file :file/repo ?repo]
+              [?file :file/path ?path]]
+         @conn repo-url)
        (map first)
        distinct))
 
 (defn set-file-content!
-  [file content]
+  [repo-url file content]
   (d/transact! conn
-    {:file/path file
-     :file/content content}))
+    [{:file/repo [:repo/url repo-url]
+      :file/path file
+      :file/content content}]))
+
+(defn get-file-content
+  [repo-url path]
+  (->> (d/q '[:find ?content
+              :in $ ?repo-url ?path
+              :where
+              [?repo :repo/url ?repo-url]
+              [?file :file/repo ?repo]
+              [?file :file/path ?path]
+              [?file :file/content ?content]
+              ]
+         @conn repo-url path)
+       (map first)
+       first))
+
+(defn sub-file
+  [path]
+  (prn {:path path})
+  (q '[:find ?content
+       :in $ ?path
+       :where
+       [_     :repo/current ?repo]
+       [?file :file/repo ?repo]
+       [?file :file/path ?path]
+       [?file :file/content ?content]]
+    conn
+    path))
+
+(defn get-all-files-content
+  [repo-url]
+  (d/q '[:find ?path ?content
+         :in $ ?repo-url
+         :where
+         [?repo :repo/url ?repo-url]
+         [?file :file/repo ?repo]
+         [?file :file/content ?content]
+         [?file :file/path ?path]
+         ]
+    @conn repo-url))
 
 (comment
   (d/transact! conn [{:db/id -1

+ 38 - 109
frontend/src/frontend/handler.cljs

@@ -19,19 +19,10 @@
 
 ;; We only support Github token now
 (defn load-file
-  ([repo-url path]
-   (util/p-handle (fs/read-file (git/get-repo-dir repo-url) path)
-                  (fn [content]
-                    (let [state @state/state
-                          state' (-> state
-                                     (assoc-in [:contents path] content)
-                                     (assoc-in [:loadings path] false)
-                                     (assoc :current-file path))]
-                      (reset! state/state state')))))
-  ([repo-url path state-handler]
-   (util/p-handle (fs/read-file (git/get-repo-dir repo-url) path)
-                  (fn [content]
-                    (state-handler content)))))
+  [repo-url path state-handler]
+  (util/p-handle (fs/read-file (git/get-repo-dir repo-url) path)
+                 (fn [content]
+                   (state-handler content))))
 
 (defn- hidden?
   [path patterns]
@@ -44,35 +35,18 @@
 
 (defn load-files
   [repo-url]
-  (prn "load files: " repo-url)
-  ;; (util/p-handle (git/list-files repo-url)
-  ;;                (fn [files]
-  ;;                  (when (> (count files) 0)
-  ;;                    (let [files (js->clj files)]
-  ;;                      (if (contains? (set files) config/hidden-file)
-  ;;                        (load-file repo-url config/hidden-file
-  ;;                                   (fn [patterns-content]
-  ;;                                     (when patterns-content
-  ;;                                       (let [patterns (string/split patterns-content #"\n")
-  ;;                                             files (remove (fn [path] (hidden? path patterns)) files)]
-  ;;                                         (db/transact-files! repo-url files)))))
-  ;;                        (p/promise (db/transact-files! repo-url files)))))))
-  )
-
-;; (defn extract-links
-;;   [form]
-;;   (let [links (atom [])]
-;;     (clojure.walk/postwalk
-;;      (fn [x]
-;;        (when (and (vector? x)
-;;                   (= "Link" (first x)))
-;;          (let [[_ {:keys [url label]}] x
-;;                [_ {:keys [protocol link]}] url
-;;                link (str protocol ":" link)]
-;;            (swap! links conj link)))
-;;        x)
-;;      form)
-;;     @links))
+  (util/p-handle (git/list-files repo-url)
+                 (fn [files]
+                   (when (> (count files) 0)
+                     (let [files (js->clj files)]
+                       (if (contains? (set files) config/hidden-file)
+                         (load-file repo-url config/hidden-file
+                                    (fn [patterns-content]
+                                      (when patterns-content
+                                        (let [patterns (string/split patterns-content #"\n")
+                                              files (remove (fn [path] (hidden? path patterns)) files)]
+                                          (db/transact-files! repo-url files)))))
+                         (p/promise (db/transact-files! repo-url files))))))))
 
 
 ;; TODO: remove this
@@ -133,22 +107,19 @@
   [repo]
   (let [token (db/get-github-token)]
     (util/p-handle
-    (do
-      (prn "Debug: cloning " repo)
-      (db/set-repo-cloning repo true)
-      (git/clone repo token))
-    (fn []
-      (db/set-repo-cloning repo false)
-      (db/mark-repo-as-cloned repo)
-      ;; load contents
-      (load-files repo))
-    (fn [e]
-      (db/set-repo-cloning repo false)
-      (prn "Clone failed, reason: " e)))))
-
-(defn reset-current-file
-  []
-  (swap! state/state assoc :current-file nil))
+     (do
+       (prn "Debug: cloning " repo)
+       (db/set-repo-cloning repo true)
+       (git/clone repo token))
+     (fn []
+       (db/set-repo-cloning repo false)
+       (db/mark-repo-as-cloned repo)
+       (db/set-current-repo! repo)
+       ;; load contents
+       (load-files repo))
+     (fn [e]
+       (db/set-repo-cloning repo false)
+       (prn "Clone failed, reason: " e)))))
 
 (defn new-notification
   [text]
@@ -192,19 +163,6 @@
       (notify-fn)
       (js/setInterval notify-fn (* 1000 60)))))
 
-(defn hide-snackbar
-  []
-  (swap! state/state assoc
-         :snackbar? false
-         :snackbar-message nil))
-
-(defn show-snackbar
-  [message]
-  (swap! state/state assoc
-         :snackbar? true
-         :snackbar-message message)
-  (js/setTimeout hide-snackbar 3000))
-
 (defn alter-file
   [repo-url file]
   (when-let [content (get-in @state/state [:repos repo-url :contents file])]
@@ -224,7 +182,7 @@
                                   (fn []
                                     (swap! state/state util/dissoc-in path)
                                     (swap! state/state assoc-in [:repos repo-url :contents file] content')
-                                    (show-snackbar "File updated!")
+                                    ;; (show-snackbar "File updated!")
                                     ;; (change-page :home)
                                     )
                                   (fn []
@@ -279,11 +237,11 @@
 
 (defn load-all-contents!
   [repo-url ok-handler]
-  (let [files (db/get-files)]
+  (let [files (db/get-repo-files repo-url)]
     (-> (p/all (for [file files]
                  (load-file repo-url file
                             (fn [content]
-                              (db/set-file-content! file content)))))
+                              (db/set-file-content! repo-url file content)))))
         (p/then
          (fn [_]
            (prn "Files are loaded!")
@@ -291,7 +249,7 @@
 
 (defn extract-all-headings
   [repo-url]
-  (let [contents (get-in @state/state [:repos repo-url :contents])]
+  (let [contents (db/get-all-files-content repo-url)]
     (vec
      (mapcat
       (fn [[file content] contents]
@@ -308,18 +266,12 @@
                           (reset! headings-atom headings)
                           (db/transact-headings! headings)))))
 
-(defn get-user-token-repos
-  []
-  (let [user (:user @state/state)
-        token (:oauth_token (first (:tokens @state/state)))
-        repos (map :url (vals (:repos @state/state)))]
-    [user token repos]))
 
-(defn sync
-  []
-  (let [[_user token repos] (get-user-token-repos)]
-    (doseq [repo repos]
-      (pull repo token))))
+;; (defn sync
+;;   []
+;;   (let [[_user token repos] (get-user-token-repos)]
+;;     (doseq [repo repos]
+;;       (pull repo token))))
 
 (defn periodically-pull-and-push
   [repo-url]
@@ -329,29 +281,6 @@
   ;; automatically push
   (periodically-push-tasks repo-url))
 
-;; (defn get-me
-;;   []
-;;   (let [{:keys [user tokens repos]} body]
-;;     (db/init)
-;;     (let [repos (map :url repos)
-;;           cloned (load-cloned?)
-;;           token (db/get-github-token)]
-;;       (doseq [[repo cloned?] cloned]
-;;         (swap! state/state
-;;                assoc-in [:repos repo :cloned?] cloned?))
-;;       (when (seq repos)
-;;         (doseq [repo-url repos]
-;;           (if (get cloned repo-url)
-;;             (periodically-pull-and-push repo-url)
-;;             (-> (clone token repo-url)
-;;                 (p/then
-;;                  (fn []
-;;                    (periodically-pull-and-push repo-url))))))))))
-
-(defn set-current-repo
-  [repo-url]
-  (swap! state/state assoc :current-repo repo-url))
-
 (defn set-route-match!
   [route]
   (swap! state/state assoc :route-match route))

+ 7 - 1
frontend/src/frontend/routes.cljs

@@ -2,7 +2,9 @@
   (:require [frontend.components.home :as home]
             [frontend.components.sidebar :as sidebar]
             [frontend.components.auth :as auth]
-            [frontend.components.repo :as repo]))
+            [frontend.components.repo :as repo]
+            [frontend.components.file :as file]
+            ))
 
 (def routes
   [["/"
@@ -16,6 +18,10 @@
     {:name :repo-add
      :view repo/add-repo}]
 
+   ["/file/:path"
+    {:name :file
+     :view file/file}]
+
    ;; TODO: edit file
    ;; Settings
    ;; ["/item/:id"