Merge remote-tracking branch 'origin/master' into refactor/common.css

This commit is contained in:
charlie
2020-12-17 19:40:25 +08:00
17 changed files with 436 additions and 386 deletions

View File

@@ -19,7 +19,8 @@
[frontend.handler.notification :as notification]
[frontend.components.editor :as editor]
[frontend.context.i18n :as i18n]
[frontend.text :as text]))
[frontend.text :as text]
[frontend.handler.page :as page-handler]))
(defn- set-format-js-loading!
[format value]
@@ -89,7 +90,7 @@
:on-click (fn []
(let [title (string/trim @input)]
(when (not (string/blank? title))
(if (db/template-exists? title)
(if (page-handler/template-exists? title)
(notification/show!
[:p "Template already exists!"]
:error)

View File

@@ -141,8 +141,8 @@
(string/lower-case current-command)))
date (get @*timestamp :date)]
(when (state/sub :editor/show-date-picker?)
[:div.flex.flex-row {:on-click (fn [e]
(util/stop e))}
[:div#date-time-picker.flex.flex-row {:on-click (fn [e]
(util/stop e))}
(ui/datepicker
date
{:deadline-or-schedule? deadline-or-schedule?

View File

@@ -463,7 +463,7 @@
[:div.flex-1
[:h1.title (t :all-pages)]
(when current-repo
(let [pages (db/get-pages-with-modified-at current-repo)]
(let [pages (page-handler/get-pages-with-modified-at current-repo)]
[:table.table-auto
[:thead
[:tr

View File

@@ -24,19 +24,39 @@
remove-files-db!
get-conn
get-files-conn
me-tx
remove-conn!]
[frontend.db.utils
date->int db->json db->string get-max-tx-id get-tx-id
group-by-page me-tx seq-flatten sort-by-pos
string->db with-repo]
group-by-page seq-flatten sort-by-pos
string->db with-repo
entity pull pull-many transact! get-key-value]
[frontend.db.model
entity pull pull-many
add-properties! add-q! add-query-component! block-and-children-transform blocks-count blocks-count-cache clean-export! clear-query-state! clear-query-state-without-refs-and-embeds! cloned? delete-blocks delete-file! delete-file-blocks! delete-file-pages! delete-file-tx delete-files delete-pages-by-files filter-only-public-pages-and-blocks get-alias-page get-all-block-contents get-all-tagged-pages get-all-tags get-all-templates get-block-and-children get-block-and-children-no-cache get-block-blocks-cache-atom get-block-by-uuid get-block-children get-block-children-ids get-block-content get-block-file get-block-immediate-children get-block-page get-block-page-end-pos get-block-parent get-block-parents get-block-referenced-blocks get-block-refs-count get-blocks-by-priority get-blocks-contents get-collapsed-blocks get-config get-custom-css get-date-scheduled-or-deadlines get-db-type get-empty-pages get-file get-file-after-blocks get-file-after-blocks-meta get-file-blocks get-file-contents get-file-last-modified-at get-file-no-sub get-file-page get-file-page-id get-file-pages get-files get-files-blocks get-files-full get-files-that-referenced-page get-journals-length get-key-value get-latest-journals get-marker-blocks get-matched-blocks get-page get-page-alias get-page-alias-names get-page-blocks get-page-blocks-cache-atom get-page-blocks-count get-page-blocks-no-cache get-page-file get-page-format get-page-name get-page-properties get-page-properties-content get-page-referenced-blocks get-page-referenced-pages get-page-unlinked-references get-pages get-pages-relation get-pages-that-mentioned-page get-pages-with-modified-at get-public-pages get-tag-pages journal-page? kv local-native-fs? mark-repo-as-cloned! page-alias-set page-blocks-transform pull-block q query-components query-entity-in-component query-state rebuild-page-blocks-children remove-custom-query! remove-key! remove-q! remove-query-component! reset-config! set-file-last-modified-at! set-new-result! sub-key-value template-exists? transact! transact-files-db! with-block-refs-count]
add-properties! block-and-children-transform blocks-count blocks-count-cache clean-export! cloned? delete-blocks
delete-file! delete-file-blocks! delete-file-pages! delete-file-tx delete-files delete-pages-by-files
filter-only-public-pages-and-blocks get-alias-page get-all-block-contents get-all-tagged-pages get-all-tags
get-all-templates get-block-and-children get-block-and-children-no-cache get-block-by-uuid get-block-children
get-block-children-ids get-block-content get-block-file get-block-immediate-children get-block-page
get-block-page-end-pos get-block-parent get-block-parents get-block-referenced-blocks get-block-refs-count
get-blocks-by-priority get-blocks-contents get-collapsed-blocks get-config get-custom-css
get-date-scheduled-or-deadlines get-db-type get-empty-pages get-file get-file-after-blocks get-file-after-blocks-meta
get-file-blocks get-file-contents get-file-last-modified-at get-file-no-sub get-file-page get-file-page-id
get-file-pages get-files get-files-blocks get-files-full get-files-that-referenced-page get-journals-length
get-latest-journals get-marker-blocks get-matched-blocks get-page get-page-alias get-page-alias-names get-page-blocks
get-page-blocks-count get-page-blocks-no-cache get-page-file get-page-format get-page-name get-page-properties
get-page-properties-content get-page-referenced-blocks get-page-referenced-pages get-page-unlinked-references
get-pages get-pages-relation get-pages-that-mentioned-page get-public-pages get-tag-pages
journal-page? local-native-fs? mark-repo-as-cloned! page-alias-set page-blocks-transform pull-block
reset-config! set-file-last-modified-at! transact-files-db! with-block-refs-count get-modified-pages]
[frontend.db.react
get-current-marker get-current-page get-current-priority get-handler-keys set-file-content! set-key-value transact-react!]
get-current-marker get-current-page get-current-priority get-handler-keys set-file-content! set-key-value
transact-react! remove-key! remove-q! remove-query-component! add-q! add-query-component! clear-query-state!
clear-query-state-without-refs-and-embeds! get-block-blocks-cache-atom get-page-blocks-cache-atom kv q
query-state query-components query-entity-in-component remove-custom-query! set-new-result! sub-key-value]
[frontend.db.query-custom
custom-query custom-query-result-transform])

View File

@@ -6,8 +6,7 @@
[frontend.state :as state]
[frontend.config :as config]
[frontend.idb :as idb]
[datascript.core :as d]
[frontend.db.utils :as db-utils]))
[datascript.core :as d]))
(defonce conns (atom {}))
@@ -64,6 +63,12 @@
(swap! conns dissoc (datascript-db repo))
(swap! conns dissoc (datascript-files-db repo)))
(defn me-tx
[db {:keys [name email avatar]}]
(util/remove-nils {:me/name name
:me/email email
:me/avatar avatar}))
(defn start!
([me repo]
(start! me repo {}))
@@ -78,6 +83,6 @@
db-type
(assoc :db/type db-type))])
(when me
(d/transact! db-conn [(db-utils/me-tx (d/db db-conn) me)]))
(d/transact! db-conn [(me-tx (d/db db-conn) me)]))
(when listen-handler (listen-handler repo)))))

View File

@@ -1,11 +1,11 @@
(ns frontend.db.debug
(:require [medley.core :as medley]
[frontend.db.model :as model]))
[frontend.db.utils :as db-utils]))
;; shortcut for query a block with string ref
(defn qb
[string-id]
(model/pull [:block/uuid (medley/uuid string-id)]))
(db-utils/pull [:block/uuid (medley/uuid string-id)]))
(comment
(defn debug!

View File

@@ -2,6 +2,7 @@
"Core db functions."
(:require [frontend.db.conn :as conn]
[frontend.db.utils :as db-utils]
[frontend.db.react :as react]
[datascript.core :as d]
[frontend.date :as date]
[medley.core :as medley]
@@ -21,228 +22,24 @@
;; TODO: extract to specific models and move data transform logic to the
;; correponding handlers.
(defn entity
([id-or-lookup-ref]
(entity (state/get-current-repo) id-or-lookup-ref))
([repo id-or-lookup-ref]
(when-let [db (conn/get-conn repo)]
(d/entity db id-or-lookup-ref))))
(defn pull
([eid]
(pull (state/get-current-repo) '[*] eid))
([selector eid]
(pull (state/get-current-repo) selector eid))
([repo selector eid]
(when-let [conn (conn/get-conn repo)]
(try
(d/pull conn
selector
eid)
(catch js/Error e
nil)))))
(defn pull-many
([eids]
(pull-many '[*] eids))
([selector eids]
(pull-many (state/get-current-repo) selector eids))
([repo selector eids]
(when-let [conn (conn/get-conn repo)]
(try
(d/pull-many conn selector eids)
(catch js/Error e
(js/console.error e))))))
(defn transact!
([tx-data]
(transact! (state/get-current-repo) tx-data))
([repo-url tx-data]
(when-not config/publishing?
(let [tx-data (->> (util/remove-nils tx-data)
(remove nil?))]
(when (seq tx-data)
(when-let [conn (conn/get-conn repo-url false)]
(d/transact! conn (vec tx-data))))))))
(defn transact-files-db!
([tx-data]
(transact! (state/get-current-repo) tx-data))
(db-utils/transact! (state/get-current-repo) tx-data))
([repo-url tx-data]
(when-not config/publishing?
(let [tx-data (->> (util/remove-nils tx-data)
(remove nil?)
(map #(dissoc % :file/handle :file/type)))]
(remove nil?)
(map #(dissoc % :file/handle :file/type)))]
(when (seq tx-data)
(when-let [conn (conn/get-files-conn repo-url)]
(d/transact! conn (vec tx-data))))))))
;; Query atom of map of Key ([repo q inputs]) -> atom
;; TODO: replace with LRUCache, only keep the latest 20 or 50 items?
(defonce query-state (atom {}))
(def ^:dynamic *query-component*)
;; key -> components
(defonce query-components (atom {}))
(defonce blocks-count-cache (atom nil))
(defn set-new-result!
[k new-result]
(when-let [result-atom (get-in @query-state [k :result])]
(reset! result-atom new-result)))
;; KV
(defn get-key-value
([key]
(get-key-value (state/get-current-repo) key))
([repo-url key]
(when-let [db (conn/get-conn repo-url)]
(some-> (d/entity db key)
key))))
(defn kv
[key value]
{:db/id -1
:db/ident key
key value})
(defn remove-key!
[repo-url key]
(transact! repo-url [[:db.fn/retractEntity [:db/ident key]]])
(set-new-result! [repo-url :kv key] nil))
(defn clear-query-state!
[]
(reset! query-state {}))
;; remove block refs, block embeds, page embeds
(defn clear-query-state-without-refs-and-embeds!
[]
(let [state @query-state
state (->> (filter (fn [[[_repo k] v]]
(contains? #{:blocks :block/block :custom} k)) state)
(into {}))]
(reset! query-state state)))
;; TODO: Add components which subscribed to a specific query
(defn add-q!
[k query inputs result-atom transform-fn query-fn inputs-fn]
(swap! query-state assoc k {:query query
:inputs inputs
:result result-atom
:transform-fn transform-fn
:query-fn query-fn
:inputs-fn inputs-fn})
result-atom)
(defn remove-q!
[k]
(swap! query-state dissoc k))
(defn add-query-component!
[key component]
(swap! query-components update key
(fn [components]
(distinct (conj components component)))))
(defn remove-query-component!
[component]
(reset!
query-components
(->> (for [[k components] @query-components
:let [new-components (remove #(= component %) components)]]
(if (empty? new-components) ; no subscribed components
(do (remove-q! k)
nil)
[k new-components]))
(keep identity)
(into {}))))
(defn get-page-blocks-cache-atom
[repo page-id]
(:result (get @query-state [repo :page/blocks page-id])))
(defn get-block-blocks-cache-atom
[repo block-id]
(:result (get @query-state [repo :block/block block-id])))
;; TODO: rename :custom to :query/custom
(defn remove-custom-query!
[repo query]
(remove-q! [repo :custom query]))
;; Reactive query
(defn query-entity-in-component
([id-or-lookup-ref]
(entity (state/get-current-repo) id-or-lookup-ref))
([repo id-or-lookup-ref]
(let [k [:entity id-or-lookup-ref]
result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(when-let [db (conn/get-conn repo)]
(let [result (d/entity db id-or-lookup-ref)
result-atom (or result-atom (atom nil))]
(set! (.-state result-atom) result)
(add-q! k nil nil result-atom identity identity identity))))))
(defn q
[repo k {:keys [use-cache? files-db? transform-fn query-fn inputs-fn]
:or {use-cache? true
files-db? false
transform-fn identity}} query & inputs]
(let [kv? (and (vector? k) (= :kv (first k)))
k (vec (cons repo k))]
(when-let [conn (if files-db?
(when-let [files-conn (conn/get-files-conn repo)]
(deref files-conn))
(conn/get-conn repo))]
(let [result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(if (and use-cache? result-atom)
result-atom
(let [result (cond
query-fn
(query-fn conn)
inputs-fn
(let [inputs (inputs-fn)]
(apply d/q query conn inputs))
kv?
(d/entity conn (last k))
(seq inputs)
(apply d/q query conn inputs)
:else
(d/q query conn))
result (transform-fn result)
result-atom (or result-atom (atom nil))]
;; Don't notify watches now
(set! (.-state result-atom) result)
(add-q! k query inputs result-atom transform-fn query-fn inputs-fn)))))))
(defn sub-key-value
([key]
(sub-key-value (state/get-current-repo) key))
([repo-url key]
(when (conn/get-conn repo-url)
(-> (q repo-url [:kv key] {} key key)
react
key))))
(defn pull-block
[id]
(let [repo (state/get-current-repo)]
(when (conn/get-conn repo)
(->
(q repo [:blocks id] {}
(react/q repo [:blocks id] {}
'[:find (pull ?block [*])
:in $ ?id
:where
@@ -256,7 +53,7 @@
(let [repo (state/get-current-repo)]
(when (conn/get-conn repo)
(some->>
(q repo [:tags] {}
(react/q repo [:tags] {}
'[:find ?name ?h ?p
:where
[?t :tag/name ?name]
@@ -297,23 +94,14 @@
(conn/get-conn repo))
(map first)))
(defn get-pages-with-modified-at
(defn get-modified-pages
[repo]
(let [now-long (tc/to-long (t/now))]
(->> (d/q
'[:find ?page-name ?modified-at
:where
[?page :page/original-name ?page-name]
[(get-else $ ?page :page/last-modified-at 0) ?modified-at]]
(conn/get-conn repo))
(seq)
(sort-by (fn [[page modified-at]]
[modified-at page]))
(reverse)
(remove (fn [[page modified-at]]
(or (util/file-page? page)
(and modified-at
(> modified-at now-long))))))))
(d/q
'[:find ?page-name ?modified-at
:where
[?page :page/original-name ?page-name]
[(get-else $ ?page :page/last-modified-at 0) ?modified-at]]
(conn/get-conn repo)))
(defn get-page-alias
[repo page-name]
@@ -344,7 +132,7 @@
[repo page-name]
(let [alias-ids (get-page-alias repo page-name)]
(when (seq alias-ids)
(->> (pull-many repo '[:page/name] alias-ids)
(->> (db-utils/pull-many repo '[:page/name] alias-ids)
(map :page/name)
distinct))))
@@ -410,7 +198,7 @@
ks (if content-level?
'[:block/uuid :block/meta :block/content :block/level]
'[:block/uuid :block/meta])
blocks (pull-many repo-url ks eids)]
blocks (db-utils/pull-many repo-url ks eids)]
(->> (filter (fn [{:block/keys [meta]}]
(>= (:start-pos meta) end-pos)) blocks)
db-utils/sort-by-pos))))
@@ -446,7 +234,7 @@
([repo path]
(when (and repo path)
(->
(q repo [:file/content path]
(react/q repo [:file/content path]
{:files-db? true
:use-cache? true}
'[:find ?content
@@ -504,17 +292,17 @@
(defn get-block-by-uuid
[uuid]
(entity [:block/uuid uuid]))
(db-utils/entity [:block/uuid uuid]))
(defn get-page-format
[page-name]
(when-let [file (:page/file (entity [:page/name page-name]))]
(when-let [path (:file/path (entity (:db/id file)))]
(when-let [file (:page/file (db-utils/entity [:page/name page-name]))]
(when-let [path (:file/path (db-utils/entity (:db/id file)))]
(format/get-format path))))
(defn page-alias-set
[repo-url page]
(when-let [page-id (:db/id (entity [:page/name page]))]
(when-let [page-id (:db/id (db-utils/entity [:page/name page]))]
(let [aliases (get-page-alias repo-url page)
aliases (if (seq aliases)
(set
@@ -553,7 +341,7 @@
(defn sort-blocks
[blocks]
(let [pages-ids (map (comp :db/id :block/page) blocks)
pages (pull-many '[:db/id :page/last-modified-at :page/name :page/original-name] pages-ids)
pages (db-utils/pull-many '[:db/id :page/last-modified-at :page/name :page/original-name] pages-ids)
pages-map (reduce (fn [acc p] (assoc acc (:db/id p) p)) {} pages)
blocks (map
(fn [block]
@@ -566,7 +354,7 @@
[repo-url marker]
(let [marker (string/upper-case marker)]
(some->>
(q repo-url [:marker/blocks marker]
(react/q repo-url [:marker/blocks marker]
{:use-cache? true}
'[:find (pull ?h [*])
:in $ ?marker
@@ -584,7 +372,7 @@
(defn get-page-properties
[page]
(when-let [page (entity [:page/name page])]
(when-let [page (db-utils/entity [:page/name page])]
(:page/properties page)))
(defn add-properties!
@@ -636,18 +424,18 @@
:or {use-cache? true
pull-keys '[*]}}]
(let [page (string/lower-case page)
page-id (or (:db/id (entity repo-url [:page/name page]))
(:db/id (entity repo-url [:page/original-name page])))
page-id (or (:db/id (db-utils/entity repo-url [:page/name page]))
(:db/id (db-utils/entity repo-url [:page/original-name page])))
db (conn/get-conn repo-url)]
(when page-id
(some->
(q repo-url [:page/blocks page-id]
(react/q repo-url [:page/blocks page-id]
{:use-cache? use-cache?
:transform-fn #(page-blocks-transform repo-url %)
:query-fn (fn [db]
(let [datoms (d/datoms db :avet :block/page page-id)
block-eids (mapv :e datoms)]
(pull-many repo-url pull-keys block-eids)))}
(db-utils/pull-many repo-url pull-keys block-eids)))}
nil)
react)))))
@@ -659,13 +447,13 @@
([repo-url page {:keys [pull-keys]
:or {pull-keys '[*]}}]
(let [page (string/lower-case page)
page-id (or (:db/id (entity repo-url [:page/name page]))
(:db/id (entity repo-url [:page/original-name page])))
page-id (or (:db/id (db-utils/entity repo-url [:page/name page]))
(:db/id (db-utils/entity repo-url [:page/original-name page])))
db (conn/get-conn repo-url)]
(when page-id
(let [datoms (d/datoms db :avet :block/page page-id)
block-eids (mapv :e datoms)]
(some->> (pull-many repo-url pull-keys block-eids)
(some->> (db-utils/pull-many repo-url pull-keys block-eids)
(page-blocks-transform repo-url)))))))
(defn get-page-blocks-count
@@ -693,18 +481,18 @@
(defn get-block-page
[repo block-id]
(when-let [block (entity repo [:block/uuid block-id])]
(entity repo (:db/id (:block/page block)))))
(when-let [block (db-utils/entity repo [:block/uuid block-id])]
(db-utils/entity repo (:db/id (:block/page block)))))
(defn get-block-page-end-pos
[repo page-name]
(or
(when-let [page-id (:db/id (entity repo [:page/name (string/lower-case page-name)]))]
(when-let [page-id (:db/id (db-utils/entity repo [:page/name (string/lower-case page-name)]))]
(when-let [db (conn/get-conn repo)]
(let [block-eids (->> (d/datoms db :avet :block/page page-id)
(mapv :e))]
(when (seq block-eids)
(let [blocks (pull-many repo '[:block/meta] block-eids)]
(let [blocks (db-utils/pull-many repo '[:block/meta] block-eids)]
(-> (last (db-utils/sort-by-pos blocks))
(get-in [:block/meta :end-pos])))))))
;; TODO: need more thoughts
@@ -714,7 +502,7 @@
[repo priority]
(let [priority (string/capitalize priority)]
(when (conn/get-conn repo)
(->> (q repo [:priority/blocks priority] {}
(->> (react/q repo [:priority/blocks priority] {}
'[:find (pull ?h [*])
:in $ ?priority
:where
@@ -761,7 +549,7 @@
(defn get-block-children-ids
[repo block-uuid]
(when-let [conn (conn/get-conn repo)]
(let [eid (:db/id (entity repo [:block/uuid block-uuid]))]
(let [eid (:db/id (db-utils/entity repo [:block/uuid block-uuid]))]
(->> (d/q
'[:find ?e1
:in $ ?e2 %
@@ -779,32 +567,32 @@
(defn get-block-immediate-children
[repo block-uuid]
(when-let [conn (conn/get-conn repo)]
(let [ids (->> (:block/children (entity repo [:block/uuid block-uuid]))
(let [ids (->> (:block/children (db-utils/entity repo [:block/uuid block-uuid]))
(map :db/id))]
(when (seq ids)
(pull-many repo '[*] ids)))))
(db-utils/pull-many repo '[*] ids)))))
(defn get-block-children
[repo block-uuid]
(when-let [conn (conn/get-conn repo)]
(let [ids (get-block-children-ids repo block-uuid)]
(when (seq ids)
(pull-many repo '[*] ids)))))
(db-utils/pull-many repo '[*] ids)))))
(defn get-block-and-children
([repo block-uuid]
(get-block-and-children repo block-uuid true))
([repo block-uuid use-cache?]
(let [block (entity repo [:block/uuid block-uuid])
(let [block (db-utils/entity repo [:block/uuid block-uuid])
page (:db/id (:block/page block))
pos (:start-pos (:block/meta block))
level (:block/level block)
pred (fn []
(let [block (entity repo [:block/uuid block-uuid])
(let [block (db-utils/entity repo [:block/uuid block-uuid])
pos (:start-pos (:block/meta block))]
(fn [data meta]
(>= (:start-pos meta) pos))))]
(some-> (q repo [:block/block block-uuid]
(some-> (react/q repo [:block/block block-uuid]
{:use-cache? use-cache?
:transform-fn #(block-and-children-transform % repo block-uuid level)
:inputs-fn (fn []
@@ -820,7 +608,7 @@
;; TODO: performance
(defn get-block-and-children-no-cache
[repo block-uuid]
(let [block (entity repo [:block/uuid block-uuid])
(let [block (db-utils/entity repo [:block/uuid block-uuid])
page (:db/id (:block/page block))
pos (:start-pos (:block/meta block))
level (:block/level block)
@@ -865,15 +653,15 @@
(defn get-page-file
[page-name]
(some-> (entity [:page/name page-name])
(some-> (db-utils/entity [:page/name page-name])
:page/file))
(defn get-block-file
[block-id]
(let [page-id (some-> (entity [:block/uuid block-id])
(let [page-id (some-> (db-utils/entity [:block/uuid block-id])
:block/page
:db/id)]
(:page/file (entity page-id))))
(:page/file (db-utils/entity page-id))))
(defn get-file-page-id
[file-path]
@@ -893,8 +681,8 @@
(defn get-page
[page-name]
(if (util/uuid-string? page-name)
(entity [:block/uuid (uuid page-name)])
(entity [:page/name page-name])))
(db-utils/entity [:block/uuid (uuid page-name)])
(db-utils/entity [:page/name page-name])))
(defn get-page-name
[file ast]
@@ -951,7 +739,7 @@
_ (.setDate date (- (.getDate date) (dec n)))
today (db-utils/date->int (js/Date.))
pages (->>
(q repo-url [:journals] {:use-cache? false}
(react/q repo-url [:journals] {:use-cache? false}
'[:find ?page-name ?journal-day
:in $ ?today
:where
@@ -976,8 +764,8 @@
[repo page]
(when (conn/get-conn repo)
(let [pages (page-alias-set repo page)
page-id (:db/id (entity [:page/name page]))
ref-pages (->> (q repo [:page/ref-pages page-id] {:use-cache? false}
page-id (:db/id (db-utils/entity [:page/name page]))
ref-pages (->> (react/q repo [:page/ref-pages page-id] {:use-cache? false}
'[:find ?ref-page-name
:in $ ?pages
:where
@@ -1030,9 +818,9 @@
(defn get-pages-that-mentioned-page
[repo page]
(when (conn/get-conn repo)
(let [page-id (:db/id (entity [:page/name page]))
(let [page-id (:db/id (db-utils/entity [:page/name page]))
pages (page-alias-set repo page)
mentioned-pages (->> (q repo [:page/mentioned-pages page-id] {:use-cache? false}
mentioned-pages (->> (react/q repo [:page/mentioned-pages page-id] {:use-cache? false}
'[:find ?mentioned-page-name
:in $ ?pages ?page-name
:where
@@ -1050,9 +838,9 @@
[page]
(when-let [repo (state/get-current-repo)]
(when (conn/get-conn repo)
(let [page-id (:db/id (entity [:page/name page]))
(let [page-id (:db/id (db-utils/entity [:page/name page]))
pages (page-alias-set repo page)]
(->> (q repo [:page/refed-blocks page-id] {}
(->> (react/q repo [:page/refed-blocks page-id] {}
'[:find (pull ?block [*])
:in $ ?pages
:where
@@ -1072,7 +860,7 @@
(when-let [date (date/journal-title->int journal-title)]
(when-let [repo (state/get-current-repo)]
(when-let [conn (conn/get-conn repo)]
(->> (q repo [:custom :scheduled-deadline journal-title] {}
(->> (react/q repo [:custom :scheduled-deadline journal-title] {}
'[:find (pull ?block [*])
:in $ ?day
:where
@@ -1107,7 +895,7 @@
[page]
(when-let [repo (state/get-current-repo)]
(when-let [conn (conn/get-conn repo)]
(let [page-id (:db/id (entity [:page/name page]))
(let [page-id (:db/id (db-utils/entity [:page/name page]))
pages (page-alias-set repo page)
pattern (re-pattern (str "(?i)" page))]
(->> (d/q
@@ -1133,7 +921,7 @@
[block-uuid]
(when-let [repo (state/get-current-repo)]
(when (conn/get-conn repo)
(->> (q repo [:block/refed-blocks block-uuid] {}
(->> (react/q repo [:block/refed-blocks block-uuid] {}
'[:find (pull ?ref-block [*])
:in $ ?block-uuid
:where
@@ -1160,7 +948,7 @@
pred)
(take limit)
db-utils/seq-flatten
(pull-many '[:block/uuid
(db-utils/pull-many '[:block/uuid
:block/content
:block/properties
:block/format
@@ -1170,16 +958,16 @@
(defn get-blocks-contents
[repo block-uuids]
(let [db (conn/get-conn repo)]
(pull-many repo '[:block/content]
(db-utils/pull-many repo '[:block/content]
(mapv (fn [id] [:block/uuid id]) block-uuids))))
(defn journal-page?
[page-name]
(:page/journal? (entity [:page/name page-name])))
(:page/journal? (db-utils/entity [:page/name page-name])))
(defn mark-repo-as-cloned!
[repo-url]
(transact!
(db-utils/transact!
[{:repo/url repo-url
:repo/cloned? true}]))
@@ -1214,7 +1002,7 @@
(defn get-db-type
[repo]
(get-key-value repo :db/type))
(db-utils/get-key-value repo :db/type))
(defn local-native-fs?
[repo]
@@ -1240,56 +1028,6 @@
db)
(db-utils/seq-flatten)))
(defn rebuild-page-blocks-children
"For performance reason, we can update the :block/children value after every operation,
but it's hard to make sure that it's correct, also it needs more time to implement it.
We can improve it if the performance is really an issue."
[repo page]
(let [blocks (->>
(get-page-blocks-no-cache repo page {:pull-keys '[:db/id :block/uuid :block/level :block/pre-block? :block/meta]})
(remove :block/pre-block?)
(map #(select-keys % [:db/id :block/uuid :block/level]))
(reverse))
original-blocks blocks]
(loop [blocks blocks
tx []
children {}
last-level 10000]
(if (seq blocks)
(let [[{:block/keys [uuid level] :as block} & others] blocks
[tx children] (cond
(< level last-level) ; parent
(let [cur-children (get children last-level)
tx (if (seq cur-children)
(vec
(concat
tx
(map
(fn [child]
[:db/add (:db/id block) :block/children [:block/uuid child]])
cur-children)))
tx)
children (-> children
(dissoc last-level)
(update level conj uuid))]
[tx children])
(> level last-level) ; child of sibling
(let [children (update children level conj uuid)]
[tx children])
:else ; sibling
(let [children (update children last-level conj uuid)]
[tx children]))]
(recur others tx children level))
;; TODO: add top-level children to the "Page" block (we might remove the Page from db schema)
(when (seq tx)
(let [delete-tx (map (fn [block]
[:db/retract (:db/id block) :block/children])
original-blocks)]
(->> (concat delete-tx tx)
(remove nil?))))))))
(defn get-all-templates
[]
(let [pred (fn [db properties]
@@ -1306,13 +1044,7 @@
[(get m "template") e]))
(into {}))))
(defn template-exists?
[title]
(when title
(let [templates (keys (get-all-templates))]
(when (seq templates)
(let [templates (map string/lower-case templates)]
(contains? (set templates) (string/lower-case title)))))))
(defonce blocks-count-cache (atom nil))
(defn blocks-count
([]
@@ -1331,7 +1063,7 @@
(->> (d/datoms conn :avet :block/uuid)
(map :v)
(map (fn [id]
(let [e (entity [:block/uuid id])]
(let [e (db-utils/entity [:block/uuid id])]
{:db/id (:db/id e)
:block/uuid id
:block/content (:block/content e)
@@ -1350,7 +1082,7 @@
(defn filter-only-public-pages-and-blocks
[db]
(let [public-pages (get-public-pages db)
contents-id (:db/id (entity [:page/name "contents"]))]
contents-id (:db/id (db-utils/entity [:page/name "contents"]))]
(when (seq public-pages)
(let [public-pages (set (conj public-pages contents-id))
page-or-block? #(contains? #{"page" "block" "me" "recent" "file"} %)
@@ -1397,7 +1129,7 @@
(defn delete-file!
[repo-url file-path]
(transact! repo-url (delete-file-tx repo-url file-path)))
(db-utils/transact! repo-url (delete-file-tx repo-url file-path)))
(defn delete-pages-by-files
[files]

View File

@@ -9,7 +9,8 @@
[cljs.reader :as reader]
[frontend.extensions.sci :as sci]
[lambdaisland.glogi :as log]
[frontend.util :as util]))
[frontend.util :as util]
[frontend.db.react :as react]))
(defn- resolve-input
[input]
@@ -42,7 +43,7 @@
(let [inputs (map resolve-input inputs)
repo (state/get-current-repo)
k [:custom query']]
(apply model/q repo k query-opts query inputs))
(apply react/q repo k query-opts query inputs))
(catch js/Error e
(println "Custom query failed: ")
(js/console.dir e))))

View File

@@ -5,19 +5,158 @@
solution.
"
(:require [frontend.db.conn :as conn]
[frontend.db.utils :as db-utils]
[frontend.db.model :as model]
[frontend.state :as state]
[frontend.date :as date]
[frontend.util :as util :refer-macros [profile] :refer [react]]
[clojure.string :as string]
[frontend.config :as config]
[frontend.format :as format]
[cljs-time.core :as t]
[cljs-time.coerce :as tc]
[frontend.utf8 :as utf8]
[datascript.core :as d]
[lambdaisland.glogi :as log]))
[lambdaisland.glogi :as log]
[frontend.db.utils :as db-utils]))
;; Query atom of map of Key ([repo q inputs]) -> atom
;; TODO: replace with LRUCache, only keep the latest 20 or 50 items?
(defonce query-state (atom {}))
(def ^:dynamic *query-component*)
;; key -> components
(defonce query-components (atom {}))
(defn set-new-result!
[k new-result]
(when-let [result-atom (get-in @query-state [k :result])]
(reset! result-atom new-result)))
;; KV
(defn kv
[key value]
{:db/id -1
:db/ident key
key value})
(defn remove-key!
[repo-url key]
(db-utils/transact! repo-url [[:db.fn/retractEntity [:db/ident key]]])
(set-new-result! [repo-url :kv key] nil))
(defn clear-query-state!
[]
(reset! query-state {}))
(defn clear-query-state-without-refs-and-embeds!
[]
(let [state @query-state
state (->> (filter (fn [[[_repo k] v]]
(contains? #{:blocks :block/block :custom} k)) state)
(into {}))]
(reset! query-state state)))
;; TODO: Add components which subscribed to a specific query
(defn add-q!
[k query inputs result-atom transform-fn query-fn inputs-fn]
(swap! query-state assoc k {:query query
:inputs inputs
:result result-atom
:transform-fn transform-fn
:query-fn query-fn
:inputs-fn inputs-fn})
result-atom)
(defn remove-q!
[k]
(swap! query-state dissoc k))
(defn add-query-component!
[key component]
(swap! query-components update key
(fn [components]
(distinct (conj components component)))))
(defn remove-query-component!
[component]
(reset!
query-components
(->> (for [[k components] @query-components
:let [new-components (remove #(= component %) components)]]
(if (empty? new-components) ; no subscribed components
(do (remove-q! k)
nil)
[k new-components]))
(keep identity)
(into {}))))
(defn get-page-blocks-cache-atom
[repo page-id]
(:result (get @query-state [repo :page/blocks page-id])))
(defn get-block-blocks-cache-atom
[repo block-id]
(:result (get @query-state [repo :block/block block-id])))
;; TODO: rename :custom to :query/custom
(defn remove-custom-query!
[repo query]
(remove-q! [repo :custom query]))
;; Reactive query
(defn query-entity-in-component
([id-or-lookup-ref]
(db-utils/entity (state/get-current-repo) id-or-lookup-ref))
([repo id-or-lookup-ref]
(let [k [:entity id-or-lookup-ref]
result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(when-let [db (conn/get-conn repo)]
(let [result (d/entity db id-or-lookup-ref)
result-atom (or result-atom (atom nil))]
(set! (.-state result-atom) result)
(add-q! k nil nil result-atom identity identity identity))))))
(defn q
[repo k {:keys [use-cache? files-db? transform-fn query-fn inputs-fn]
:or {use-cache? true
files-db? false
transform-fn identity}} query & inputs]
(let [kv? (and (vector? k) (= :kv (first k)))
k (vec (cons repo k))]
(when-let [conn (if files-db?
(when-let [files-conn (conn/get-files-conn repo)]
(deref files-conn))
(conn/get-conn repo))]
(let [result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(if (and use-cache? result-atom)
result-atom
(let [result (cond
query-fn
(query-fn conn)
inputs-fn
(let [inputs (inputs-fn)]
(apply d/q query conn inputs))
kv?
(d/entity conn (last k))
(seq inputs)
(apply d/q query conn inputs)
:else
(d/q query conn))
result (transform-fn result)
result-atom (or result-atom (atom nil))]
;; Don't notify watches now
(set! (.-state result-atom) result)
(add-q! k query inputs result-atom transform-fn query-fn inputs-fn)))))))
;; TODO: Extract several parts to handlers
@@ -39,7 +178,7 @@
(date/journal-name))]
(when page
(let [page-name (util/url-decode (string/lower-case page))]
(model/entity (if tag?
(db-utils/entity (if tag?
[:tag/name page-name]
[:page/name page-name]))))))
@@ -106,7 +245,7 @@
(apply concat
(for [{:block/keys [ref-pages]} blocks]
(map (fn [page]
(when-let [page (model/entity [:page/name (:page/name page)])]
(when-let [page (db-utils/entity [:page/name (:page/name page)])]
[:page/refed-blocks (:db/id page)]))
ref-pages)))
@@ -126,14 +265,14 @@
(filter (fn [v]
(and (= (first v) (state/get-current-repo))
(= (second v) :custom)))
(keys @model/query-state))
(keys @query-state))
(map (fn [v]
(vec (drop 1 v)))))
block-blocks (some->>
(filter (fn [v]
(and (= (first v) (state/get-current-repo))
(= (second v) :block/block)))
(keys @model/query-state))
(keys @query-state))
(map (fn [v]
(vec (drop 1 v)))))]
(->>
@@ -162,7 +301,7 @@
handler-keys (get-handler-keys handler-opts)]
(doseq [handler-key handler-keys]
(let [handler-key (vec (cons repo-url handler-key))]
(when-let [cache (get @model/query-state handler-key)]
(when-let [cache (get @query-state handler-key)]
(let [{:keys [query inputs transform-fn query-fn inputs-fn]} cache]
(when (or query query-fn)
(let [new-result (->
@@ -177,7 +316,7 @@
(apply d/q query db inputs))
(keyword? query)
(model/get-key-value repo-url query)
(db-utils/get-key-value repo-url query)
(seq inputs)
(apply d/q query db inputs)
@@ -185,7 +324,7 @@
:else
(d/q query db))
transform-fn)]
(model/set-new-result! handler-key new-result))))))))))
(set-new-result! handler-key new-result))))))))))
(catch js/Error e
;; FIXME: check error type and notice user
(log/error :db/transact! e)))))
@@ -193,9 +332,18 @@
(defn set-key-value
[repo-url key value]
(if value
(transact-react! repo-url [(model/kv key value)]
(transact-react! repo-url [(kv key value)]
{:key [:kv key]})
(model/remove-key! repo-url key)))
(remove-key! repo-url key)))
(defn sub-key-value
([key]
(sub-key-value (state/get-current-repo) key))
([repo-url key]
(when (conn/get-conn repo-url)
(-> (q repo-url [:kv key] {} key key)
react
key))))
(defn set-file-content!
[repo path content]

View File

@@ -5,7 +5,9 @@
[clojure.string :as string]
[datascript.transit :as dt]
[frontend.util :as util]
[frontend.date :as date]))
[frontend.date :as date]
[frontend.db.conn :as conn]
[frontend.config :as config]))
;; transit serialization
@@ -21,12 +23,6 @@
(defn string->db [s]
(dt/read-transit-str s))
(defn me-tx
[db {:keys [name email avatar]}]
(util/remove-nils {:me/name name
:me/email email
:me/avatar avatar}))
(defn seq-flatten [col]
(flatten (seq col)))
@@ -59,3 +55,55 @@
(map (fn [block]
(assoc block :block/repo repo))
blocks))
(defn entity
([id-or-lookup-ref]
(entity (state/get-current-repo) id-or-lookup-ref))
([repo id-or-lookup-ref]
(when-let [db (conn/get-conn repo)]
(d/entity db id-or-lookup-ref))))
(defn pull
([eid]
(pull (state/get-current-repo) '[*] eid))
([selector eid]
(pull (state/get-current-repo) selector eid))
([repo selector eid]
(when-let [conn (conn/get-conn repo)]
(try
(d/pull conn
selector
eid)
(catch js/Error e
nil)))))
(defn pull-many
([eids]
(pull-many '[*] eids))
([selector eids]
(pull-many (state/get-current-repo) selector eids))
([repo selector eids]
(when-let [conn (conn/get-conn repo)]
(try
(d/pull-many conn selector eids)
(catch js/Error e
(js/console.error e))))))
(defn transact!
([tx-data]
(transact! (state/get-current-repo) tx-data))
([repo-url tx-data]
(when-not config/publishing?
(let [tx-data (->> (util/remove-nils tx-data)
(remove nil?))]
(when (seq tx-data)
(when-let [conn (conn/get-conn repo-url false)]
(d/transact! conn (vec tx-data))))))))
(defn get-key-value
([key]
(get-key-value (state/get-current-repo) key))
([repo-url key]
(when-let [db (conn/get-conn repo-url)]
(some-> (d/entity db key)
key))))

View File

@@ -1,5 +1,5 @@
(ns frontend.db-mixins
(:require [frontend.db.model :as db]))
(:require [frontend.db.react :as db]))
(def query
{:wrap-render

View File

@@ -1792,7 +1792,8 @@
(fn [state e]
(when-let [repo (state/get-current-repo)]
(let [blocks (seq (state/get-selection-blocks))]
(if (seq blocks)
(cond
(seq blocks)
(let [ids (map (fn [block] (when-let [id (dom/attr block "blockid")]
(medley/uuid id))) blocks)
ids (->> (mapcat #(let [children (vec (db/get-block-children-ids repo %))]
@@ -1847,6 +1848,11 @@
{:key :block/change
:data (map (fn [block] (assoc block :block/page page)) blocks)}
[[file-path new-content]])))
(gdom/getElement "date-time-picker")
nil
:else
(cycle-collapse! state e))))))
(defn bulk-make-todos

View File

@@ -22,7 +22,9 @@
[frontend.fs :as fs]
[promesa.core :as p]
[lambdaisland.glogi :as log]
[frontend.format.mldoc :as mldoc]))
[frontend.format.mldoc :as mldoc]
[cljs-time.core :as t]
[cljs-time.coerce :as tc]))
(defn- get-directory
[journal?]
@@ -467,3 +469,25 @@
'())
new-pages (take 12 (distinct (cons page pages)))]
(db/set-key-value repo :recent/pages new-pages)))
(defn template-exists?
[title]
(when title
(let [templates (keys (db/get-all-templates))]
(when (seq templates)
(let [templates (map string/lower-case templates)]
(contains? (set templates) (string/lower-case title)))))))
(defn get-pages-with-modified-at
[repo]
(let [now-long (tc/to-long (t/now))]
(->> (db/get-modified-pages repo)
(seq)
(sort-by (fn [[page modified-at]]
[modified-at page]))
(reverse)
(remove (fn [[page modified-at]]
(or (util/file-page? page)
(and modified-at
(> modified-at now-long))))))))

View File

@@ -252,6 +252,56 @@
(load-repo-to-db! repo-url {:first-clone? first-clone?
:diffs diffs})))
(defn rebuild-page-blocks-children
"For performance reason, we can update the :block/children value after every operation,
but it's hard to make sure that it's correct, also it needs more time to implement it.
We can improve it if the performance is really an issue."
[repo page]
(let [blocks (->>
(db/get-page-blocks-no-cache repo page {:pull-keys '[:db/id :block/uuid :block/level :block/pre-block? :block/meta]})
(remove :block/pre-block?)
(map #(select-keys % [:db/id :block/uuid :block/level]))
(reverse))
original-blocks blocks]
(loop [blocks blocks
tx []
children {}
last-level 10000]
(if (seq blocks)
(let [[{:block/keys [uuid level] :as block} & others] blocks
[tx children] (cond
(< level last-level) ; parent
(let [cur-children (get children last-level)
tx (if (seq cur-children)
(vec
(concat
tx
(map
(fn [child]
[:db/add (:db/id block) :block/children [:block/uuid child]])
cur-children)))
tx)
children (-> children
(dissoc last-level)
(update level conj uuid))]
[tx children])
(> level last-level) ; child of sibling
(let [children (update children level conj uuid)]
[tx children])
:else ; sibling
(let [children (update children last-level conj uuid)]
[tx children]))]
(recur others tx children level))
;; TODO: add top-level children to the "Page" block (we might remove the Page from db schema)
(when (seq tx)
(let [delete-tx (map (fn [block]
[:db/retract (:db/id block) :block/children])
original-blocks)]
(->> (concat delete-tx tx)
(remove nil?))))))))
(defn transact-react-and-alter-file!
[repo tx transact-option files]
(spec/validate :repos/url repo)
@@ -263,7 +313,7 @@
tx
transact-option)
(when (seq pages)
(let [children-tx (mapcat #(db/rebuild-page-blocks-children repo %) pages)]
(let [children-tx (mapcat #(rebuild-page-blocks-children repo %) pages)]
(when (seq children-tx)
(db/transact! repo children-tx))))
(when (seq files)

View File

@@ -381,7 +381,7 @@
[on? on-click]
[:a {:on-click on-click}
[:span.relative.inline-block.flex-shrink-0.h-6.w-11.border-2.border-transparent.rounded-full.cursor-pointer.transition-colors.ease-in-out.duration-200.focus:outline-none.focus:shadow-outline
{:aria-checked "false", :tabindex "0", :role "checkbox"
{:aria-checked "false", :tab-index "0", :role "checkbox"
:class (if on? "bg-indigo-600" "bg-gray-200")}
[:span.inline-block.h-5.w-5.rounded-full.bg-white.shadow.transform.transition.ease-in-out.duration-200
{:class (if on? "translate-x-5" "translate-x-0")

View File

@@ -179,6 +179,11 @@
(constantly true))]
(merge attributes {:selectable-fn selectable-fn})))
(defn- input-or-select?
[]
(when-let [elem js/document.activeElement]
(or (util/input? elem) (util/select? elem))))
(rum/defc date-picker < rum/reactive
(mixins/event-mixin
(fn [state]
@@ -187,26 +192,31 @@
state
{;; enter, current day
13 (fn [state e]
(when on-change
(when (and on-change
(not (input-or-select?)))
(when-not deadline-or-schedule?
(on-change e @*internal-model))))
;; left, previous day
37 (fn [state e]
(swap! *internal-model inc-date -1))
(when-not (input-or-select?)
(swap! *internal-model inc-date -1)))
;; right, next day
39 (fn [state e]
(swap! *internal-model inc-date 1))
(when-not (input-or-select?)
(swap! *internal-model inc-date 1)))
;; up, one week ago
38 (fn [state e]
(swap! *internal-model inc-week -1))
(when-not (input-or-select?)
(swap! *internal-model inc-week -1)))
;; down, next week
40 (fn [state e]
(swap! *internal-model inc-week 1))}
(when-not (input-or-select?)
(swap! *internal-model inc-week 1)))}
{:all-handler (fn [e key-code]
(when (contains? #{13 37 38 39 40} key-code)
(when (contains? #{13} key-code)
(util/stop e)))}))))
{:init (fn [state]
(reset! *internal-model (first (:rum/args state)))

View File

@@ -372,6 +372,11 @@
#{"INPUT" "TEXTAREA"}
(gobj/get node "tagName"))))
(defn select?
[node]
(when node
(= "SELECT" (gobj/get node "tagName"))))
(defn details-or-summary?
[node]
(when node