events.cljs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. (ns frontend.handler.events
  2. (:refer-clojure :exclude [run!])
  3. (:require [clojure.core.async :as async]
  4. [clojure.set :as set]
  5. [datascript.core :as d]
  6. [frontend.components.diff :as diff]
  7. [frontend.handler.plugin :as plugin-handler]
  8. [frontend.components.plugins :as plugin]
  9. [frontend.components.encryption :as encryption]
  10. [frontend.components.git :as git-component]
  11. [frontend.components.shell :as shell]
  12. [frontend.components.search :as search]
  13. [frontend.config :as config]
  14. [frontend.db :as db]
  15. [frontend.db-schema :as db-schema]
  16. [frontend.db.conn :as conn]
  17. [frontend.extensions.srs :as srs]
  18. [frontend.fs.nfs :as nfs]
  19. [frontend.handler.common :as common-handler]
  20. [frontend.handler.editor :as editor-handler]
  21. [frontend.handler.notification :as notification]
  22. [frontend.handler.page :as page-handler]
  23. [frontend.handler.ui :as ui-handler]
  24. [frontend.modules.shortcut.core :as st]
  25. [frontend.commands :as commands]
  26. [frontend.spec :as spec]
  27. [frontend.state :as state]
  28. [frontend.ui :as ui]
  29. [frontend.util :as util]
  30. [rum.core :as rum]
  31. ["semver" :as semver]
  32. [frontend.modules.instrumentation.posthog :as posthog]
  33. [frontend.mobile.util :as mobile-util]
  34. [frontend.encrypt :as encrypt]
  35. [promesa.core :as p]))
  36. ;; TODO: should we move all events here?
  37. (defn show-install-error!
  38. [repo-url title]
  39. (spec/validate :repos/url repo-url)
  40. (notification/show!
  41. [:p.content
  42. title
  43. " "
  44. [:span.mr-2
  45. (util/format
  46. "Please make sure that you've installed the logseq app for the repo %s on GitHub. "
  47. repo-url)
  48. (ui/button
  49. "Install Logseq on GitHub"
  50. :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))]]
  51. :error
  52. false))
  53. (defmulti handle first)
  54. (defmethod handle :repo/install-error [[_ repo-url title]]
  55. (show-install-error! repo-url title))
  56. (defmethod handle :modal/encryption-setup-dialog [[_ repo-url close-fn]]
  57. (state/set-modal!
  58. (encryption/encryption-setup-dialog repo-url close-fn)))
  59. (defmethod handle :modal/encryption-input-secret-dialog [[_ repo-url db-encrypted-secret close-fn]]
  60. (state/set-modal!
  61. (encryption/encryption-input-secret-dialog
  62. repo-url
  63. db-encrypted-secret
  64. close-fn)))
  65. (defmethod handle :graph/added [[_ repo]]
  66. ;; TODO: add ast/version to db
  67. (let [_conn (conn/get-conn repo false)
  68. ; ast-version (d/datoms @conn :aevt :ast/version)
  69. ]
  70. (db/set-key-value repo :ast/version db-schema/ast-version)))
  71. (defmethod handle :graph/migrated [[_ _repo]]
  72. (js/alert "Graph migrated."))
  73. (defn get-local-repo
  74. []
  75. (when-let [repo (state/get-current-repo)]
  76. (when (config/local-db? repo)
  77. repo)))
  78. (defn ask-permission
  79. [repo]
  80. (when
  81. (and (not (util/electron?))
  82. (not (mobile-util/is-native-platform?)))
  83. (fn [close-fn]
  84. [:div
  85. [:p
  86. "Grant native filesystem permission for directory: "
  87. [:b (config/get-local-dir repo)]]
  88. (ui/button
  89. "Grant"
  90. :class "ui__modal-enter"
  91. :on-click (fn []
  92. (nfs/check-directory-permission! repo)
  93. (close-fn)))])))
  94. (defmethod handle :modal/nfs-ask-permission []
  95. (when-let [repo (get-local-repo)]
  96. (state/set-modal! (ask-permission repo))))
  97. (defonce *query-properties (atom {}))
  98. (rum/defc query-properties-settings-inner < rum/reactive
  99. {:will-unmount (fn [state]
  100. (reset! *query-properties {})
  101. state)}
  102. [block shown-properties all-properties _close-fn]
  103. (let [query-properties (rum/react *query-properties)]
  104. [:div.p-4
  105. [:div.font-bold "Properties settings for this query:"]
  106. (for [property all-properties]
  107. (let [property-value (get query-properties property)
  108. shown? (if (nil? property-value)
  109. (contains? shown-properties property)
  110. property-value)]
  111. [:div.flex.flex-row.m-2.justify-between.align-items
  112. [:div (name property)]
  113. [:div.mt-1 (ui/toggle shown?
  114. (fn []
  115. (let [value (not shown?)]
  116. (swap! *query-properties assoc property value)
  117. (editor-handler/set-block-query-properties!
  118. (:block/uuid block)
  119. all-properties
  120. property
  121. value)))
  122. true)]]))]))
  123. (defn query-properties-settings
  124. [block shown-properties all-properties]
  125. (fn [close-fn]
  126. (query-properties-settings-inner block shown-properties all-properties close-fn)))
  127. (defmethod handle :modal/set-query-properties [[_ block all-properties]]
  128. (let [block-properties (some-> (get-in block [:block/properties :query-properties])
  129. (common-handler/safe-read-string "Parsing query properties failed"))
  130. shown-properties (if (seq block-properties)
  131. (set block-properties)
  132. (set all-properties))
  133. shown-properties (set/intersection (set all-properties) shown-properties)]
  134. (state/set-modal! (query-properties-settings block shown-properties all-properties))))
  135. (defmethod handle :modal/show-cards [_]
  136. (state/set-modal! srs/global-cards))
  137. (defmethod handle :modal/show-themes-modal [_]
  138. (plugin/open-select-theme!))
  139. (rum/defc modal-output
  140. [content]
  141. content)
  142. (defmethod handle :modal/show [[_ content]]
  143. (state/set-modal! #(modal-output content)))
  144. (defmethod handle :modal/set-git-username-and-email [[_ _content]]
  145. (state/set-modal! git-component/set-git-username-and-email))
  146. (defmethod handle :page/title-property-changed [[_ old-title new-title]]
  147. (page-handler/rename! old-title new-title))
  148. (defmethod handle :page/create-today-journal [[_ _repo]]
  149. (p/let [_ (page-handler/create-today-journal!)]
  150. (ui-handler/re-render-root!)))
  151. (defmethod handle :file/not-matched-from-disk [[_ path disk-content db-content]]
  152. (state/clear-edit!)
  153. (when-let [repo (state/get-current-repo)]
  154. (when (and disk-content db-content
  155. (not= (util/trim-safe disk-content) (util/trim-safe db-content)))
  156. (state/set-modal! #(diff/local-file repo path disk-content db-content)))))
  157. (defmethod handle :modal/display-file-version [[_ path content hash]]
  158. (p/let [content (when content (encrypt/decrypt content))]
  159. (state/set-modal! #(git-component/file-specific-version path hash content))))
  160. (defmethod handle :after-db-restore [[_ repos]]
  161. (mapv (fn [{url :url}]
  162. ;; compare :ast/version
  163. (let [db (conn/get-conn url)
  164. ast-version (:v (first (d/datoms db :aevt :ast/version)))]
  165. (when (and (not= config/local-repo url)
  166. (or (nil? ast-version)
  167. (. semver lt ast-version db-schema/ast-version)))
  168. (notification/show!
  169. [:p.content
  170. (util/format "DB-schema updated, Please re-index repo [%s]" url)]
  171. :warning
  172. false))))
  173. repos))
  174. (defmethod handle :notification/show [[_ {:keys [content status clear?]}]]
  175. (notification/show! content status clear?))
  176. (defmethod handle :command/run [_]
  177. (when (util/electron?)
  178. (state/set-modal! shell/shell)))
  179. (defmethod handle :go/search [_]
  180. (state/set-modal! search/search-modal
  181. {:fullscreen? false
  182. :close-btn? false}))
  183. (defmethod handle :go/plugins [_]
  184. (plugin/open-plugins-modal!))
  185. (defmethod handle :go/plugins-waiting-lists [_]
  186. (plugin/open-waiting-updates-modal!))
  187. (defmethod handle :redirect-to-home [_]
  188. (page-handler/create-today-journal!))
  189. (defmethod handle :instrument [[_ {:keys [type payload]}]]
  190. (posthog/capture type payload))
  191. (defmethod handle :exec-plugin-cmd [[_ {:keys [pid cmd action]}]]
  192. (commands/exec-plugin-simple-command! pid cmd action))
  193. (defmethod handle :shortcut-handler-refreshed [[_]]
  194. (when-not @st/*inited?
  195. (reset! st/*inited? true)
  196. (st/consume-pending-shortcuts!)))
  197. (defmethod handle :mobile/keyboard-will-show [[_]]
  198. (when (and (state/get-left-sidebar-open?)
  199. (state/editing?))
  200. (state/set-left-sidebar-open! false)))
  201. (defmethod handle :mobile/keyboard-did-show [[_]]
  202. (when-let [input (state/get-input)]
  203. (util/make-el-into-viewport input)))
  204. (defmethod handle :plugin/consume-updates [[_ id pending? updated?]]
  205. (let [downloading? (:plugin/updates-downloading? @state/state)]
  206. (when-let [coming (and (not downloading?)
  207. (get-in @state/state [:plugin/updates-coming id]))]
  208. (notification/show!
  209. (str "Checked: " (:title coming))
  210. :success))
  211. (if (and updated? downloading?)
  212. ;; try to start consume downloading item
  213. (if-let [n (state/get-next-selected-coming-update)]
  214. (plugin-handler/check-or-update-marketplace-plugin
  215. (assoc n :only-check false :error-code nil)
  216. (fn [^js e] (js/console.error "[Download Err]" n e)))
  217. (plugin-handler/close-updates-downloading))
  218. ;; try to start consume pending item
  219. (if-let [n (second (first (:plugin/updates-pending @state/state)))]
  220. (plugin-handler/check-or-update-marketplace-plugin
  221. (assoc n :only-check true :error-code nil)
  222. (fn [^js e]
  223. (notification/show! (.toString e) :error)
  224. (js/console.error "[Check Err]" n e)))
  225. ;; try to open waiting updates list
  226. (when (and pending? (seq (state/all-available-coming-updates)))
  227. (plugin/open-waiting-updates-modal!))))))
  228. (defn run!
  229. []
  230. (let [chan (state/get-events-chan)]
  231. (async/go-loop []
  232. (let [payload (async/<! chan)]
  233. (try
  234. (handle payload)
  235. (catch js/Error error
  236. (let [type :handle-system-events/failed]
  237. (js/console.error (str type) (clj->js payload) "\n" error)
  238. (state/pub-event! [:instrument {:type type
  239. :payload payload
  240. :error error}])))))
  241. (recur))
  242. chan))