repo.cljs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. (ns frontend.handler.repo
  2. "System-component-like ns that manages user's repos/graphs"
  3. (:refer-clojure :exclude [clone])
  4. (:require [cljs-bean.core :as bean]
  5. [clojure.string :as string]
  6. [electron.ipc :as ipc]
  7. [frontend.config :as config]
  8. [frontend.date :as date]
  9. [frontend.db :as db]
  10. [frontend.db.persist :as db-persist]
  11. [frontend.db.react :as react]
  12. [frontend.db.restore :as db-restore]
  13. [frontend.handler.global-config :as global-config-handler]
  14. [frontend.handler.graph :as graph-handler]
  15. [frontend.handler.notification :as notification]
  16. [frontend.handler.repo-config :as repo-config-handler]
  17. [frontend.handler.route :as route-handler]
  18. [frontend.handler.ui :as ui-handler]
  19. [frontend.idb :as idb]
  20. [frontend.persist-db :as persist-db]
  21. [frontend.search :as search]
  22. [frontend.state :as state]
  23. [frontend.undo-redo :as undo-redo]
  24. [frontend.util :as util]
  25. [frontend.util.text :as text-util]
  26. [logseq.common.config :as common-config]
  27. [logseq.db :as ldb]
  28. [logseq.db.frontend.schema :as db-schema]
  29. [promesa.core :as p]))
  30. ;; Project settings should be checked in two situations:
  31. ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file)
  32. ;; 2. Git pulls the new change (fn: load-files)
  33. (defn remove-repo!
  34. [{:keys [url] :as repo} & {:keys [switch-graph?]
  35. :or {switch-graph? true}}]
  36. (let [current-repo (state/get-current-repo)
  37. db-based? (config/db-based-graph? url)]
  38. (when (or (config/local-file-based-graph? url) db-based?)
  39. (p/do!
  40. (idb/clear-local-db! url) ; clear file handles
  41. (db/remove-conn! url)
  42. (db-persist/delete-graph! url)
  43. (search/remove-db! url)
  44. (state/delete-repo! repo)
  45. (when switch-graph?
  46. (if (= current-repo url)
  47. (do
  48. (state/set-current-repo! nil)
  49. (when-let [graph (:url (first (state/get-repos)))]
  50. (notification/show! (str "Removed graph "
  51. (pr-str (text-util/get-graph-name-from-path url))
  52. ". Redirecting to graph "
  53. (pr-str (text-util/get-graph-name-from-path graph)))
  54. :success)
  55. (state/pub-event! [:graph/switch graph {:persist? false}])))
  56. (notification/show! (str "Removed graph " (pr-str (text-util/get-graph-name-from-path url))) :success)))))))
  57. (defn start-repo-db-if-not-exists!
  58. [repo & {:as opts}]
  59. (state/set-current-repo! repo)
  60. (db/start-db-conn! repo (assoc opts
  61. :db-graph? (config/db-based-graph? repo)
  62. :listen-handler (fn [conn]
  63. (undo-redo/listen-db-changes! repo conn)))))
  64. (defn restore-and-setup-repo!
  65. "Restore the db of a graph from the persisted data, and setup. Create a new
  66. conn, or replace the conn in state with a new one."
  67. [repo & {:as opts}]
  68. (p/do!
  69. (state/set-db-restoring! true)
  70. (db-restore/restore-graph! repo opts)
  71. (repo-config-handler/restore-repo-config! repo)
  72. (when (config/global-config-enabled?)
  73. (global-config-handler/restore-global-config!))
  74. ;; Don't have to unlisten the old listener, as it will be destroyed with the conn
  75. (when-not (true? (:ignore-style? opts))
  76. (ui-handler/add-style-if-exists!))
  77. (when-not config/publishing?
  78. (state/set-db-restoring! false))))
  79. (defn rebuild-index!
  80. [url]
  81. (when-not (state/unlinked-dir? (config/get-repo-dir url))
  82. (when url
  83. (search/reset-indice! url)
  84. (db/remove-conn! url)
  85. (react/clear-query-state!)
  86. (-> (p/do! (db-persist/delete-graph! url))
  87. (p/catch (fn [error]
  88. (prn "Delete repo failed, error: " error)))))))
  89. (defn re-index!
  90. [nfs-rebuild-index! ok-handler]
  91. (when-let [repo (state/get-current-repo)]
  92. (state/reset-parsing-state!)
  93. (let [dir (config/get-repo-dir repo)]
  94. (when-not (state/unlinked-dir? dir)
  95. (route-handler/redirect-to-home!)
  96. (let [local? (config/local-file-based-graph? repo)]
  97. (if local?
  98. (nfs-rebuild-index! repo ok-handler)
  99. (rebuild-index! repo))
  100. (js/setTimeout
  101. (route-handler/redirect-to-home!)
  102. 500))))))
  103. (defn get-repos
  104. []
  105. (p/let [nfs-dbs (db-persist/get-all-graphs)
  106. nfs-dbs (map (fn [db]
  107. (let [graph-name (:name db)]
  108. {:url graph-name
  109. :metadata (:metadata db)
  110. :root (config/get-local-dir graph-name)
  111. :nfs? true}))
  112. nfs-dbs)
  113. nfs-dbs (and (seq nfs-dbs)
  114. (cond (util/electron?)
  115. (p/chain
  116. (ipc/ipc :inflateGraphsInfo (ldb/write-transit-str nfs-dbs))
  117. ldb/read-transit-str)
  118. ;(mobile-util/native-platform?)
  119. ;(util-fs/inflate-graphs-info nfs-dbs)
  120. :else
  121. nfs-dbs))]
  122. (seq (bean/->clj nfs-dbs))))
  123. (defn combine-local-&-remote-graphs
  124. [local-repos remote-repos]
  125. (when-let [repos' (seq (concat (map (fn [{:keys [sync-meta metadata] :as repo}]
  126. (let [graph-id (some-> (or (:kv/value metadata)
  127. (second sync-meta)) str)]
  128. (if graph-id (assoc repo :GraphUUID graph-id) repo)))
  129. local-repos)
  130. (some->> remote-repos
  131. (map #(assoc % :remote? true)))))]
  132. (let [app-major-schema-version (str (:major (db-schema/parse-schema-version db-schema/version)))
  133. repos' (group-by :url repos')
  134. repos'' (mapcat (fn [[k vs]]
  135. (if (some? k)
  136. (let [remote-repos (filter :remote? vs)
  137. version-matched-remote-repo
  138. (first
  139. (filter
  140. #(= app-major-schema-version (:GraphSchemaVersion %))
  141. remote-repos))]
  142. [(merge (first vs) (second vs) version-matched-remote-repo)])
  143. vs))
  144. repos')]
  145. (sort-by (fn [repo]
  146. (let [graph-name (or (:GraphName repo)
  147. (last (string/split (:root repo) #"/")))]
  148. [(:remote? repo) (string/lower-case graph-name)])) repos''))))
  149. (defn get-detail-graph-info
  150. [url]
  151. (when-let [graphs (seq (and url (combine-local-&-remote-graphs
  152. (state/get-repos)
  153. (state/get-remote-file-graphs))))]
  154. (first (filter #(when-let [url' (:url %)]
  155. (= url url')) graphs))))
  156. (defn refresh-repos!
  157. []
  158. (p/let [repos (get-repos)
  159. repos' (combine-local-&-remote-graphs
  160. repos
  161. (concat
  162. (state/get-rtc-graphs)
  163. (when-not (or (util/mobile?) util/web-platform?)
  164. (state/get-remote-file-graphs))))]
  165. (state/set-repos! repos')
  166. repos'))
  167. (defn graph-ready!
  168. ;; FIXME: Call electron that the graph is loaded, an ugly implementation for redirect to page when graph is restored
  169. [graph]
  170. (when (util/electron?)
  171. (ipc/ipc "graphReady" graph)))
  172. (defn graph-already-exists?
  173. "Checks to see if given db graph name already exists"
  174. [graph-name]
  175. (let [full-graph-name (string/lower-case (str config/db-version-prefix graph-name))]
  176. (some #(= (some-> (:url %) string/lower-case) full-graph-name) (state/get-repos))))
  177. (defn- create-db [full-graph-name {:keys [file-graph-import?]}]
  178. (->
  179. (p/let [config (common-config/create-config-for-db-graph config/config-default-content)
  180. _ (persist-db/<new full-graph-name
  181. (cond-> {:config config
  182. :graph-git-sha config/revision}
  183. file-graph-import? (assoc :import-type :file-graph)))
  184. _ (start-repo-db-if-not-exists! full-graph-name)
  185. _ (state/add-repo! {:url full-graph-name :root (config/get-local-dir full-graph-name)})
  186. _ (restore-and-setup-repo! full-graph-name {:file-graph-import? file-graph-import?})
  187. _ (when-not file-graph-import? (route-handler/redirect-to-home!))
  188. _ (repo-config-handler/set-repo-config-state! full-graph-name config/config-default-content)
  189. ;; TODO: handle global graph
  190. _ (state/pub-event! [:init/commands])
  191. _ (when-not file-graph-import? (state/pub-event! [:page/create (date/today) {:redirect? false}]))]
  192. (state/pub-event! [:shortcut/refresh])
  193. (route-handler/redirect-to-home!)
  194. (ui-handler/re-render-root!)
  195. (graph-handler/settle-metadata-to-local! {:created-at (js/Date.now)})
  196. (prn "New db created: " full-graph-name)
  197. full-graph-name)
  198. (p/catch (fn [error]
  199. (notification/show! "Create graph failed." :error)
  200. (js/console.error error)))))
  201. (defn new-db!
  202. "Handler for creating a new database graph"
  203. ([graph] (new-db! graph {}))
  204. ([graph opts]
  205. (let [full-graph-name (str config/db-version-prefix graph)]
  206. (if (graph-already-exists? graph)
  207. (state/pub-event! [:notification/show
  208. {:content (str "The graph '" graph "' already exists. Please try again with another name.")
  209. :status :error}])
  210. (create-db full-graph-name opts)))))
  211. (defn fix-broken-graph!
  212. [graph]
  213. (state/<invoke-db-worker :thread-api/fix-broken-graph graph))
  214. (defn gc-graph!
  215. [graph]
  216. (p/do!
  217. (state/<invoke-db-worker :thread-api/gc-graph graph)
  218. (state/pub-event! [:notification/show
  219. {:content "Graph gc successfully!"
  220. :status :success}])))