graph.cljs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. (ns frontend.handler.graph
  2. "Provides util handler fns for graph view"
  3. (:require [clojure.set :as set]
  4. [clojure.string :as string]
  5. [frontend.db :as db]
  6. [frontend.db.model :as db-model]
  7. [frontend.state :as state]
  8. [frontend.util :as util]
  9. [frontend.handler.property.util :as pu]
  10. [frontend.config :as config]
  11. [frontend.storage :as storage]
  12. [logseq.graph-parser.db :as gp-db]
  13. [logseq.db.sqlite.create-graph :as sqlite-create-graph]
  14. [logseq.common.util :as common-util]
  15. [logseq.db :as ldb]
  16. [frontend.components.title :as title]))
  17. (defn- build-links
  18. [links]
  19. (map (fn [[from to]]
  20. {:source from
  21. :target to})
  22. links))
  23. (defn- build-nodes
  24. [dark? current-page page-links tags nodes namespaces]
  25. (let [parents (set (map last namespaces))
  26. current-page (or current-page "")
  27. pages (set (flatten nodes))]
  28. (->>
  29. pages
  30. (remove nil?)
  31. (mapv (fn [p]
  32. (let [p (str p)
  33. current-page? (= p current-page)
  34. color (case [dark? current-page?] ; FIXME: Put it into CSS
  35. [false false] "#999"
  36. [false true] "#045591"
  37. [true false] "#93a1a1"
  38. [true true] "#ffffff")
  39. color (if (contains? tags p)
  40. (if dark? "orange" "green")
  41. color)
  42. n (get page-links p 1)
  43. size (int (* 8 (max 1.0 (js/Math.cbrt n))))]
  44. (cond->
  45. {:id p
  46. :label p
  47. :size size
  48. :color color}
  49. (contains? parents p)
  50. (assoc :parent true))))))))
  51. ;; slow
  52. (defn- uuid-or-asset?
  53. [id]
  54. (or (util/uuid-string? id)
  55. (string/starts-with? id "../assets/")
  56. (= id "..")
  57. (string/starts-with? id "assets/")
  58. (string/ends-with? id ".gif")
  59. (string/ends-with? id ".jpg")
  60. (string/ends-with? id ".png")))
  61. (defn- remove-uuids-and-files!
  62. [nodes]
  63. (remove
  64. (fn [node] (uuid-or-asset? (:id node)))
  65. nodes))
  66. (defn- normalize-page-name
  67. [{:keys [nodes links page-name->title]}]
  68. (let [links (->>
  69. (map
  70. (fn [{:keys [source target]}]
  71. (let [source (get page-name->title source)
  72. target (get page-name->title target)]
  73. (when (and source target)
  74. {:source source :target target})))
  75. links)
  76. (remove nil?))
  77. nodes (->> (remove-uuids-and-files! nodes)
  78. (util/distinct-by (fn [node] (:id node)))
  79. (map (fn [node]
  80. (if-let [title (get page-name->title (:id node))]
  81. (assoc node :id title :label title)
  82. nil)))
  83. (remove nil?))]
  84. {:nodes nodes
  85. :links links}))
  86. (defn build-global-graph
  87. [theme {:keys [journal? orphan-pages? builtin-pages? excluded-pages? created-at-filter]}]
  88. (let [dark? (= "dark" theme)
  89. current-page (or (:block/name (db/get-current-page)) "")]
  90. (when-let [repo (state/get-current-repo)]
  91. (let [relation (db/get-pages-relation repo journal?)
  92. tagged-pages (map (fn [[x y]] [x (common-util/page-name-sanity-lc y)]) (db-model/get-all-tagged-pages repo))
  93. namespaces (map (fn [[x y]] [x (common-util/page-name-sanity-lc y)]) (db/get-all-namespace-relation repo))
  94. tags (set (map second tagged-pages))
  95. full-pages (db/get-all-pages repo)
  96. full-pages-map (into {} (map (juxt :block/name identity) full-pages))
  97. all-pages (map title/block-unique-title full-pages)
  98. page-name->title (zipmap (map :block/name full-pages) all-pages)
  99. created-ats (map :block/created-at full-pages)
  100. ;; build up nodes
  101. full-pages'
  102. (cond->> full-pages
  103. created-at-filter
  104. (filter #(<= (:block/created-at %) (+ (apply min created-ats) created-at-filter)))
  105. (not journal?)
  106. (remove ldb/journal?)
  107. (not excluded-pages?)
  108. (remove (fn [p] (true? (pu/get-block-property-value p :logseq.property/exclude-from-graph-view)))))
  109. links (concat (seq relation)
  110. (seq tagged-pages)
  111. (seq namespaces))
  112. linked (set (flatten links))
  113. build-in-pages (->> (if (config/db-based-graph? repo) sqlite-create-graph/built-in-pages-names gp-db/built-in-pages-names)
  114. (map string/lower-case)
  115. set)
  116. nodes (cond->> (map :block/name full-pages')
  117. (not builtin-pages?)
  118. (remove (fn [p] (contains? build-in-pages (string/lower-case p))))
  119. (not orphan-pages?)
  120. (filter #(contains? linked (string/lower-case %))))
  121. page-links (reduce (fn [m [k v]] (-> (update m k inc)
  122. (update v inc))) {} links)
  123. links (build-links (remove (fn [[_ to]] (nil? to)) links))
  124. nodes (build-nodes dark? (string/lower-case current-page) page-links tags nodes namespaces)]
  125. (-> {:nodes (map #(assoc % :block/created-at (get-in full-pages-map [(:id %) :block/created-at])) nodes)
  126. :links links
  127. :page-name->title page-name->title}
  128. normalize-page-name
  129. (assoc :all-pages
  130. {:created-at-min (apply min created-ats)
  131. :created-at-max (apply max created-ats)}))))))
  132. (defn build-page-graph
  133. [page theme show-journal]
  134. (let [dark? (= "dark" theme)]
  135. (when-let [repo (state/get-current-repo)]
  136. (let [page-entity (db/entity page)
  137. page-id (:db/id page-entity)
  138. tags (if (config/db-based-graph? repo)
  139. (set (map #(:block/name (db/entity repo (:db/id %)))
  140. (:block/tags page-entity)))
  141. (:tags (:block/properties page-entity)))
  142. tags (remove #(= page %) tags)
  143. ref-pages (db/get-page-referenced-pages repo page-id)
  144. mentioned-pages (db/get-pages-that-mentioned-page repo page-id show-journal)
  145. namespaces (map (fn [[x y]] [x (common-util/page-name-sanity-lc y)]) (db/get-all-namespace-relation repo))
  146. links (concat
  147. namespaces
  148. (map (fn [[p _aliases]]
  149. [page p]) ref-pages)
  150. (map (fn [[p _aliases]]
  151. [p page]) mentioned-pages)
  152. (map (fn [tag]
  153. [page tag])
  154. tags))
  155. other-pages (->> (concat (map first ref-pages)
  156. (map first mentioned-pages))
  157. (remove nil?)
  158. (set))
  159. other-pages-links (mapcat
  160. (fn [page]
  161. (let [page-id (:db/id (db/get-page page))
  162. ref-pages (-> (map first (db/get-page-referenced-pages repo page-id))
  163. (set)
  164. (set/intersection other-pages))
  165. mentioned-pages (-> (map first (db/get-pages-that-mentioned-page repo page-id show-journal))
  166. (set)
  167. (set/intersection other-pages))]
  168. (concat
  169. (map (fn [p] [page p]) ref-pages)
  170. (map (fn [p] [p page]) mentioned-pages))))
  171. other-pages)
  172. links (->> (concat links other-pages-links)
  173. (remove nil?)
  174. (distinct)
  175. (build-links))
  176. nodes (->> (concat
  177. [page]
  178. (map first ref-pages)
  179. (map first mentioned-pages)
  180. tags)
  181. (remove nil?)
  182. (distinct))
  183. nodes (build-nodes dark? page links (set tags) nodes namespaces)
  184. full-pages (db/get-all-pages repo)
  185. all-pages (map common-util/get-page-title full-pages)
  186. page-name->title (zipmap (map :block/name full-pages) all-pages)]
  187. (normalize-page-name
  188. {:nodes nodes
  189. :links links
  190. :page-name->title page-name->title})))))
  191. (defn build-block-graph
  192. "Builds a citation/reference graph for a given block uuid."
  193. [block theme]
  194. (when-let [repo (state/get-current-repo)]
  195. (let [dark? (= "dark" theme)
  196. ref-blocks (db/get-block-referenced-blocks block)
  197. namespaces (map (fn [[x y]] [x (common-util/page-name-sanity-lc y)]) (db/get-all-namespace-relation repo))
  198. other-blocks (->> (concat (map first ref-blocks))
  199. (remove nil?)
  200. (set))
  201. other-blocks-links (mapcat
  202. (fn [block]
  203. (let [ref-blocks (-> (map first (db/get-block-referenced-blocks block))
  204. (set)
  205. (set/intersection other-blocks))]
  206. (concat
  207. (map (fn [p] [block p]) ref-blocks))))
  208. other-blocks)
  209. links (concat
  210. (->> other-blocks-links
  211. (remove nil?)
  212. (distinct)
  213. (build-links))
  214. namespaces)
  215. nodes (->> (concat
  216. [block]
  217. (map first ref-blocks))
  218. (remove nil?)
  219. (distinct)
  220. ;; FIXME: get block tags
  221. )
  222. nodes (build-nodes dark? block links #{} nodes namespaces)]
  223. (normalize-page-name
  224. {:nodes nodes
  225. :links links}))))
  226. (defn n-hops
  227. "Get all nodes that are n hops from nodes (a collection of node ids)"
  228. [{:keys [links] :as graph} nodes level]
  229. (let [search-nodes (fn [forward?]
  230. (let [links (group-by (if forward? :source :target) links)]
  231. (loop [nodes nodes
  232. level level]
  233. (if (zero? level)
  234. nodes
  235. (recur (distinct (apply concat nodes
  236. (map
  237. (fn [id]
  238. (->> (get links id) (map (if forward? :target :source))))
  239. nodes)))
  240. (dec level))))))
  241. nodes (concat (search-nodes true) (search-nodes false))
  242. nodes (set nodes)]
  243. (update graph :nodes
  244. (fn [full-nodes]
  245. (filter (fn [node] (contains? nodes (:id node)))
  246. full-nodes)))))
  247. (defn settle-metadata-to-local!
  248. [m]
  249. (when-let [repo (state/get-current-repo)]
  250. (try
  251. (let [k :ls-graphs-metadata
  252. ret (or (storage/get k) {})
  253. ret (update ret repo merge m {:_v (js/Date.now)})]
  254. (storage/set k ret))
  255. (catch js/Error e
  256. (js/console.warn e)))))
  257. (defn get-metadata-local
  258. []
  259. (let [k :ls-graphs-metadata]
  260. (storage/get k)))