repo.cljs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. (ns frontend.components.repo
  2. (:require [clojure.string :as string]
  3. [frontend.components.commit :as commit]
  4. [frontend.components.encryption :as encryption]
  5. [frontend.components.svg :as svg]
  6. [frontend.components.widgets :as widgets]
  7. [frontend.config :as config]
  8. [frontend.context.i18n :as i18n]
  9. [frontend.db :as db]
  10. [frontend.encrypt :as e]
  11. [frontend.handler.common :as common-handler]
  12. [frontend.handler.export :as export-handler]
  13. [frontend.handler.page :as page-handler]
  14. [frontend.handler.repo :as repo-handler]
  15. [frontend.handler.route :as route-handler]
  16. [frontend.handler.web.nfs :as nfs-handler]
  17. [frontend.modules.shortcut.core :as shortcut]
  18. [frontend.state :as state]
  19. [frontend.ui :as ui]
  20. [frontend.util :as util]
  21. [frontend.version :as version]
  22. [reitit.frontend.easy :as rfe]
  23. [rum.core :as rum]
  24. [frontend.mobile.util :as mobile-util]))
  25. (rum/defc add-repo
  26. [args]
  27. (if-let [graph-types (get-in args [:query-params :graph-types])]
  28. (let [graph-types-s (->> (string/split graph-types #",")
  29. (mapv keyword))]
  30. (when (seq graph-types-s)
  31. (widgets/add-graph :graph-types graph-types-s)))
  32. (widgets/add-graph)))
  33. (rum/defc repos < rum/reactive
  34. []
  35. (let [repos (->> (state/sub [:me :repos])
  36. (remove #(= (:url %) config/local-repo)))
  37. repos (util/distinct-by :url repos)]
  38. (rum/with-context [[t] i18n/*tongue-context*]
  39. (if (seq repos)
  40. [:div#graphs
  41. [:h1.title "All Graphs"]
  42. [:p.ml-2.opacity-70
  43. (if (state/github-authed?)
  44. "A \"graph\" in Logseq could be either a local directory or a git repo."
  45. "A \"graph\" in Logseq means a local directory.")]
  46. [:div.pl-1.content.mt-3
  47. [:div.flex.flex-row.my-4
  48. (when (or (nfs-handler/supported?)
  49. (mobile-util/is-native-platform?))
  50. [:div.mr-8
  51. (ui/button
  52. (t :open-a-directory)
  53. :on-click #(page-handler/ls-dir-files! shortcut/refresh!))])
  54. (when (and (state/logged?) (not (util/electron?)))
  55. (ui/button
  56. "Add another git repo"
  57. :href (rfe/href :repo-add nil {:graph-types "github"})
  58. :intent "logseq"))]
  59. (for [{:keys [id url] :as repo} repos]
  60. (let [local? (config/local-db? url)]
  61. [:div.flex.justify-between.mb-1 {:key id}
  62. (if local?
  63. [:a
  64. (config/get-local-dir url)]
  65. [:a {:target "_blank"
  66. :href url}
  67. (db/get-repo-path url)])
  68. [:div.controls
  69. (when (e/encrypted-db? url)
  70. [:a.control {:title "Show encryption information about this graph"
  71. :on-click (fn []
  72. (state/set-modal! (encryption/encryption-dialog url)))}
  73. "🔐"])
  74. [:a.text-gray-400.ml-4 {:title "No worries, unlink this graph will clear its cache only, it does not remove your files on the disk."
  75. :on-click (fn []
  76. (repo-handler/remove-repo! repo))}
  77. "Unlink"]]]))]]
  78. (widgets/add-graph)))))
  79. (defn refresh-cb []
  80. (page-handler/create-today-journal!)
  81. (shortcut/refresh!))
  82. (rum/defc sync-status < rum/reactive
  83. {:did-mount (fn [state]
  84. (js/setTimeout common-handler/check-changed-files-status 1000)
  85. state)}
  86. [repo]
  87. (when (and repo
  88. (string/starts-with? repo "https://"))
  89. (let [changed-files (state/sub [:repo/changed-files repo])
  90. should-push? (seq changed-files)
  91. git-status (state/sub [:git/status repo])
  92. pushing? (= :pushing git-status)
  93. pulling? (= :pulling git-status)
  94. git-failed? (contains?
  95. #{:push-failed
  96. :clone-failed
  97. :checkout-failed
  98. :fetch-failed
  99. :merge-failed}
  100. git-status)
  101. push-failed? (= :push-failed git-status)
  102. last-pulled-at (db/sub-key-value repo :git/last-pulled-at)
  103. ;; db-persisted? (state/sub [:db/persisted? repo])
  104. editing? (seq (state/sub :editor/editing?))]
  105. [:div.flex-row.flex.items-center.cp__repo-indicator
  106. (when pushing? svg/loading)
  107. (ui/dropdown
  108. (fn [{:keys [toggle-fn]}]
  109. [:div.cursor.w-2.h-2.sync-status.mr-2
  110. {:class (cond
  111. git-failed?
  112. "bg-red-500"
  113. (or
  114. ;; (not db-persisted?)
  115. editing?
  116. should-push? pushing?)
  117. "bg-orange-400"
  118. :else
  119. "bg-green-600")
  120. :style {:border-radius "50%"
  121. :margin-top 2}
  122. :on-mouse-over
  123. (fn [e]
  124. (toggle-fn)
  125. (js/setTimeout common-handler/check-changed-files-status 0))}])
  126. (fn [{:keys [toggle-fn]}]
  127. (rum/with-context [[t] i18n/*tongue-context*]
  128. [:div.p-2.rounded-md.shadow-xs.bg-base-3.flex.flex-col.sync-content
  129. {:on-mouse-leave toggle-fn}
  130. [:div
  131. [:div
  132. (cond
  133. push-failed?
  134. [:p (t :git/push-failed)]
  135. (and should-push? (seq changed-files))
  136. [:div.changes
  137. [:ul.overflow-y-auto {:style {:max-height 250}}
  138. (for [file changed-files]
  139. [:li {:key (str "sync-" file)}
  140. [:div.flex.flex-row.justify-between.align-items
  141. [:a {:href (rfe/href :file {:path file})}
  142. file]
  143. [:a.ml-4.text-sm.mt-1
  144. {:on-click (fn [e]
  145. (export-handler/download-file! file))}
  146. [:span (t :download)]]]])]]
  147. :else
  148. [:p (t :git/local-changes-synced)])]
  149. ;; [:a.text-sm.font-bold {:href "/diff"} "Check diff"]
  150. [:div.flex.flex-row.justify-between.align-items.mt-2
  151. (ui/button (t :git/push)
  152. :on-click (fn [] (state/set-modal! commit/add-commit-message)))
  153. (when pushing? svg/loading)]]
  154. [:hr]
  155. [:div
  156. (when-not (string/blank? last-pulled-at)
  157. [:p {:style {:font-size 12}} (t :git/last-pull)
  158. (str ": " last-pulled-at)])
  159. [:div.flex.flex-row.justify-between.align-items
  160. (ui/button (t :git/pull)
  161. :on-click (fn [] (repo-handler/pull-current-repo)))
  162. (when pulling? svg/loading)]
  163. [:a.mt-5.text-sm.opacity-50.block
  164. {:on-click (fn []
  165. (export-handler/export-repo-as-zip! repo))}
  166. (t :repo/download-zip)]
  167. [:p.pt-2.text-sm.opacity-50
  168. (t :git/version) (str " " version/version)]]])))])))
  169. (rum/defc repos-dropdown < rum/reactive
  170. [toggle-dropdown-f]
  171. (when-let [current-repo (state/sub :git/current-repo)]
  172. (rum/with-context [[t] i18n/*tongue-context*]
  173. (let [get-repo-name (fn [repo]
  174. (if (config/local-db? repo)
  175. (config/get-local-dir repo)
  176. (db/get-repo-path repo)))
  177. repos (state/sub [:me :repos])
  178. repos (remove (fn [r] (= config/local-repo (:url r))) repos)
  179. switch-repos (remove (fn [repo]
  180. (= current-repo (:url repo)))
  181. repos)
  182. repo-links (mapv
  183. (fn [{:keys [id url]}]
  184. {:title (get-repo-name url)
  185. :options {:class "ml-1"
  186. :on-click (fn []
  187. (repo-handler/push-if-auto-enabled! (state/get-current-repo))
  188. (state/set-current-repo! url)
  189. ;; load config
  190. (common-handler/reset-config! url nil)
  191. (shortcut/refresh!)
  192. (when-not (= :draw (state/get-current-route))
  193. (route-handler/redirect-to-home!)))}})
  194. switch-repos)
  195. links (concat repo-links
  196. [(when (seq switch-repos)
  197. {:hr true})
  198. {:title (t :new-graph)
  199. :options {:href (rfe/href :repo-add)}}
  200. {:title (t :all-graphs)
  201. :options {:href (rfe/href :repos)}}
  202. (let [nfs-repo? (config/local-db? current-repo)]
  203. (when (and nfs-repo?
  204. (not= current-repo config/local-repo)
  205. (or (nfs-handler/supported?)
  206. (mobile-util/is-native-platform?)))
  207. {:title (t :sync-from-local-files)
  208. :options {:on-click
  209. (fn []
  210. (state/pub-event!
  211. [:modal/show
  212. [:div {:style {:max-width 700}}
  213. [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
  214. (ui/button
  215. "Yes"
  216. :on-click (fn []
  217. (state/close-modal!)
  218. (nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]]))}}))
  219. {:title (t :re-index)
  220. :options {:on-click (fn []
  221. (state/pub-event!
  222. [:modal/show
  223. [:div {:style {:max-width 700}}
  224. [:p "Re-index will discard the current graph, and then processes all the files again as they are currently stored on disk. You will lose unsaved changes and it might take a while. Continue?"]
  225. (ui/button
  226. "Yes"
  227. :on-click (fn []
  228. (state/close-modal!)
  229. (repo-handler/re-index!
  230. nfs-handler/rebuild-index!
  231. page-handler/create-today-journal!)))]]))}}])]
  232. (when (seq repos)
  233. (ui/dropdown-with-links
  234. (fn [{:keys [toggle-fn]}]
  235. [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:on-click toggle-fn}
  236. (ui/icon "database mr-3" {:style {:font-size 20}
  237. :id "database-icon"})
  238. [:div.graphs
  239. [:span#repo-switch.block.pr-2.whitespace-nowrap
  240. [:span
  241. (let [repo-name (get-repo-name current-repo)
  242. repo-name (if (or (util/electron?)
  243. (mobile-util/is-native-platform?))
  244. (last
  245. (string/split repo-name #"/"))
  246. repo-name)]
  247. [:span#repo-name.font-medium {:title repo-name} repo-name])
  248. [:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]]]])
  249. links
  250. (cond->
  251. {:modal-class (util/hiccup->class
  252. "origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")}
  253. (seq switch-repos)
  254. (assoc :links-header [:div.font-medium.text-sm.opacity-70.px-4.py-2
  255. "Switch to:"]))))))))