DB helpers

This commit is contained in:
Tienson Qin
2020-03-22 15:41:44 +08:00
parent c60191ccd1
commit 65dce77d65
7 changed files with 207 additions and 259 deletions

View File

@@ -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
;; []

View File

@@ -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)
;; ))))

View File

@@ -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)))}]]]

View File

@@ -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]]]
]
]]))

View File

@@ -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

View File

@@ -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))

View File

@@ -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"