diff --git a/web/src/frontend/components/agenda.cljs b/web/src/frontend/components/agenda.cljs index 9252eb880..16359612a 100644 --- a/web/src/frontend/components/agenda.cljs +++ b/web/src/frontend/components/agenda.cljs @@ -53,69 +53,65 @@ (rum/defq agenda < {:q (fn [state] (db/sub-agenda))} [state tasks] - (let [tasks-ids (db/seq-flatten tasks) - tasks (db/pull-many tasks-ids)] - (sidebar/sidebar - [:div#agenda - [:h2.mb-3 "Agenda"] - (if (seq tasks) - [:div.ml-1 - (let [parent-tasks (block/group-by-parent (block/sort-tasks tasks))] - (for [[parent tasks] parent-tasks] - (let [parent (cond - (string? parent) - parent + (sidebar/sidebar + [:div#agenda + [:h2.mb-3 "Agenda"] + (if (seq tasks) + [:div.ml-1 + (let [parent-tasks (block/group-by-parent (block/sort-tasks tasks))] + (for [[parent tasks] parent-tasks] + (let [parent (cond + (string? parent) + parent - (and (map? parent) - (:label parent)) - (title-cp (:label parent)) + (and (map? parent) + (:label parent)) + (title-cp (:label parent)) - :else - "uncategorized")] - [:div.mt-10 - [:h4.mb-3.text-gray-500 parent] - (for [{:heading/keys [uuid marker title priority level tags children timestamps meta] :as task} tasks] - [:div.mb-2 - {:key (str "task-" uuid) - :style {:padding-left 8 - :padding-right 8}} - [:div.column - [:div.row {:style {:align-items "center"}} - (case marker - (list "DOING" "IN-PROGRESS" "TODO") - (ui/checkbox {:on-change (fn [_] - ;; FIXME: Log timestamp - ;; (handler/check marker (:pos meta)) - )}) + :else + "uncategorized")] + [:div.mt-10 + [:h4.mb-3.text-gray-500 parent] + (for [{:heading/keys [uuid marker title priority level tags children timestamps meta repo file] :as task} tasks] + [:div.mb-2 + {:key (str "task-" uuid) + :style {:padding-left 8 + :padding-right 8}} + [:div.column + [:div.row {:style {:align-items "center"}} + (case marker + (list "DOING" "IN-PROGRESS" "TODO") + (ui/checkbox {:on-change (fn [_] + ;; FIXME: Log timestamp + (handler/check repo file marker (:pos meta)))}) - "WAIT" - [:span {:style {:font-weight "bold"}} - "WAIT"] + "WAIT" + [:span {:style {:font-weight "bold"}} + "WAIT"] - "DONE" - (do - (prn marker) - (ui/checkbox {:checked true - :on-change (fn [_] - ;; FIXME: Log timestamp - ;; (handler/uncheck marker (:pos meta)) - )})) + "DONE" + (ui/checkbox {:checked true + :on-change (fn [_] + ;; FIXME: Log timestamp + (handler/uncheck repo file (:pos meta)) + )}) - nil) - [:div.row.ml-2 - (if priority - [:span.priority.mr-1 - (str "#[" priority "]")]) - (title-cp title) - (marker-cp marker) - (when (seq tags) - (tags-cp tags))]] - (when (seq timestamps) - (timestamps-cp timestamps)) + nil) + [:div.row.ml-2 + (if priority + [:span.priority.mr-1 + (str "#[" priority "]")]) + (title-cp title) + (marker-cp marker) + (when (seq tags) + (tags-cp tags))]] + (when (seq timestamps) + (timestamps-cp timestamps)) - ;; FIXME: parse error - ;; (when (seq children) - ;; (children-cp children)) + ;; FIXME: parse error + ;; (when (seq children) + ;; (children-cp children)) - ]])])))] - "Empty")]))) + ]] + )])))] + "Empty")])) diff --git a/web/src/frontend/db.cljs b/web/src/frontend/db.cljs index 5d3b88bae..630240d5b 100644 --- a/web/src/frontend/db.cljs +++ b/web/src/frontend/db.cljs @@ -63,17 +63,16 @@ (js/localStorage.setItem datascript-db (db->string db))) (defn reset-conn! [db] - (reset! conn db) - (posh/posh! conn)) + (reset! conn db)) (d/listen! conn :persistence (fn [tx-report] ;; FIXME do not notify with nil as db-report ;; FIXME do not notify if tx-data is empty - (prn "db changed.") (when-let [db (:db-after tx-report)] - (js/setTimeout #(do - (persist db) - (posh/posh! conn)) 0)))) + (prn "DB changed") + (js/setTimeout (fn [] + (posh/posh! conn) + (persist db)) 0)))) ;; (new TextEncoder().encode('foo')).length (defn db-size @@ -217,7 +216,7 @@ ([eids] (pull-many '[*] eids)) ([selector eids] - (d/pull-many (d/db conn) selector eids))) + (posh/pull-many conn selector eids))) (defn q [query & inputs] @@ -366,18 +365,40 @@ (defn sub-agenda ([] (sub-agenda :week)) + ([time] + (let [duration (case time + :today [] + :week [] + :month []) + tasks-ids (-> @(q '[:find ?h + :where + (or [?h :heading/marker "TODO"] + [?h :heading/marker "DOING"] + [?h :heading/marker "IN-PROGRESS"] + [?h :heading/marker "DONE"])] + conn) + seq-flatten)] + (pull-many tasks-ids)))) + +(defn get-agenda + ([] + (get-agenda :week)) ([time] (let [duration (case time :today [] :week [] :month [])] - (q '[:find ?h - :where - (or [?h :heading/marker "TODO"] - [?h :heading/marker "DOING"] - [?h :heading/marker "IN-PROGRESS"] - [?h :heading/marker "DONE"])] - conn)))) + (d/q '[:find (pull ?h [*]) + :where + (or [?h :heading/marker "TODO"] + [?h :heading/marker "DOING"] + [?h :heading/marker "IN-PROGRESS"] + [?h :heading/marker "DONE"])] + @conn)))) + +(defn entity + [id-or-lookup-ref] + (d/entity (d/db conn) id-or-lookup-ref)) (comment (d/transact! conn [{:db/id -1 diff --git a/web/src/frontend/git.cljs b/web/src/frontend/git.cljs index aa9747f02..2c68d3144 100644 --- a/web/src/frontend/git.cljs +++ b/web/src/frontend/git.cljs @@ -35,6 +35,21 @@ {:dir (get-repo-dir repo-url) :ref "HEAD"}))) +(defn fetch + [repo-url token] + (js/git.fetch (with-auth token + {:dir (get-repo-dir repo-url) + :ref "master" + :singleBranch true}))) + +(defn log + [repo-url token depth] + (js/git.log (with-auth token + {:dir (get-repo-dir repo-url) + :ref "master" + :depth depth + :singleBranch true}))) + (defn pull [repo-url token] (js/git.pull (with-auth token diff --git a/web/src/frontend/handler.cljs b/web/src/frontend/handler.cljs index f48b7fafa..fa32fa02f 100644 --- a/web/src/frontend/handler.cljs +++ b/web/src/frontend/handler.cljs @@ -14,7 +14,8 @@ [promesa.core :as p] [cljs-bean.core :as bean] [reitit.frontend.easy :as rfe] - [goog.crypt.base64 :as b64]) + [goog.crypt.base64 :as b64] + [goog.object :as gobj]) (:import [goog.events EventHandler])) ;; We only support Github token now @@ -52,22 +53,44 @@ ;; TODO: remove this (declare load-repo-to-db!) +(defn get-latest-commit + [handler] + (-> (git/log (db/get-current-repo) + (db/get-github-token) + 1) + (.then (fn [commits] + (handler (first commits)))) + (.catch (fn [error] + (prn "get latest commit failed: " error))))) + +(defonce latest-commit (atom nil)) + +;; TODO: Maybe replace with fetch? +;; TODO: callback hell (defn pull [repo-url token] (util/p-handle (git/pull repo-url token) (fn [result] - ;; TODO: diff - (-> (load-files repo-url) - (p/then - (fn [] - (load-repo-to-db! repo-url))))))) + (get-latest-commit + (fn [commit] + (when (or (nil? @latest-commit) + (and @latest-commit + commit + (not= (gobj/get commit "oid") + (gobj/get @latest-commit "oid")))) + (prn "New commit oid: " (gobj/get commit "oid")) + (-> (load-files repo-url) + (p/then + (fn [] + (load-repo-to-db! repo-url))))) + (reset! latest-commit commit)))))) (defn periodically-pull [repo-url] (when-let [token (db/get-github-token)] (pull repo-url token) (js/setInterval #(pull repo-url token) - (* 60 1000)))) + (* 10 1000)))) (defn add-transaction [tx] @@ -84,24 +107,18 @@ "Gitnotes auto save tasks.\n\n" (string/join "\n" transactions)))) -(defn periodically-push-tasks - [repo-url] - (let [token (db/get-github-token) - push (fn [] - (let [transactions (:tasks-transactions @state/state)] - (when (seq transactions) - (git/add-commit-push - repo-url - config/tasks-org - (transactions->commit-msg transactions) - token - (fn [] - (prn "Commit tasks to Github.") - (clear-transactions!)) - (fn [] - (prn "Failed to push."))))))] - (js/setInterval push - (* 5 1000)))) +(defn push + [repo-url file message] + (let [token (db/get-github-token)] + (git/add-commit-push + repo-url + file + message + token + (fn [] + (prn "Push successfully!")) + (fn [] + (prn "Failed to push."))))) (defn clone [repo] @@ -196,34 +213,38 @@ (clone repo-url)) (defn check - [repo-url file marker pos] - (let [token (db/get-github-token)] - (when-let [content (get-in @state/state [:repos repo-url :contents file])] + [repo file marker pos] + (let [repo (db/entity (:db/id repo)) + file (db/entity (:db/id file)) + repo-url (:repo/url repo) + file (:file/path file) + token (db/get-github-token)] + (when-let [content (db/get-file-content repo-url file)] (let [content' (str (subs content 0 pos) (-> (subs content pos) (string/replace-first marker "DONE")))] - ;; TODO: optimize, only update the specific block - ;; (build-tasks content' file) + (db/set-file-content! repo-url file content') (util/p-handle (fs/write-file (git/get-repo-dir repo-url) file content') (fn [_] - (swap! state/state assoc-in [:repos repo-url :contents file] content') - (add-transaction (util/format "`%s` marked as DONE." marker)))))))) + (push repo-url file (util/format "`%s` marked as DONE." marker)))))))) (defn uncheck - [repo-url file pos] - (let [token (db/get-github-token)] - (when-let [content (get-in @state/state [:repos repo-url :contents file])] + [repo file pos] + (let [repo (db/entity (:db/id repo)) + file (db/entity (:db/id file)) + repo-url (:repo/url repo) + file (:file/path file) + token (db/get-github-token)] + (when-let [content (db/get-file-content repo-url file)] (let [content' (str (subs content 0 pos) (-> (subs content pos) (string/replace-first "DONE" "TODO")))] - ;; TODO: optimize, only update the specific block - ;; (build-tasks content' file) + (db/set-file-content! repo-url file content') (util/p-handle (fs/write-file (git/get-repo-dir repo-url) file content') (fn [_] - (swap! state/state assoc-in [:repos repo-url :contents file] content') - (add-transaction "DONE rollbacks to TODO."))))))) + (push repo-url file "DONE rollbacks to TODO."))))))) (defn extract-headings [repo-url file content] @@ -274,14 +295,6 @@ ;; (doseq [repo repos] ;; (pull repo token)))) -(defn periodically-pull-and-push - [repo-url] - ;; automatically pull - (periodically-pull repo-url) - - ;; automatically push - (periodically-push-tasks repo-url)) - (defn get-github-access-token ([] (util/fetch (str config/api "token/github") @@ -307,7 +320,7 @@ [repo] (p/then (clone repo) (fn [] - (periodically-pull-and-push repo)))) + (periodically-pull repo)))) (defn set-route-match! [route] @@ -320,4 +333,4 @@ (db/set-current-repo! first-repo)) (let [repos (db/get-repos)] (doseq [repo repos] - (periodically-pull-and-push repo)))) + (periodically-pull repo))))