state.cljs 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410
  1. (ns frontend.state
  2. "Provides main application state, fns associated to set and state based rum
  3. cursors"
  4. (:require [cljs-bean.core :as bean]
  5. [cljs.core.async :as async :refer [>!]]
  6. [cljs.spec.alpha :as s]
  7. [clojure.set :as set]
  8. [clojure.string :as string]
  9. [datascript.core :as d]
  10. [dommy.core :as dom]
  11. [electron.ipc :as ipc]
  12. [frontend.db.conn-state :as db-conn-state]
  13. [frontend.db.transact :as db-transact]
  14. [frontend.flows :as flows]
  15. [frontend.mobile.util :as mobile-util]
  16. [frontend.rum :as r]
  17. [frontend.spec.storage :as storage-spec]
  18. [frontend.storage :as storage]
  19. [frontend.util :as util]
  20. [frontend.util.cursor :as cursor]
  21. [goog.dom :as gdom]
  22. [goog.object :as gobj]
  23. [logseq.common.config :as common-config]
  24. [logseq.db :as ldb]
  25. [logseq.db.frontend.entity-plus :as entity-plus]
  26. [logseq.db.sqlite.util :as sqlite-util]
  27. [logseq.shui.dialog.core :as shui-dialog]
  28. [logseq.shui.ui :as shui]
  29. [promesa.core :as p]
  30. [rum.core :as rum]))
  31. (defonce *profile-state (volatile! {}))
  32. (defonce *db-worker (atom nil))
  33. (defn- <invoke-db-worker*
  34. [qkw direct-pass-args? args-list]
  35. (let [worker @*db-worker]
  36. (when (nil? worker)
  37. (prn :<invoke-db-worker-error qkw)
  38. (throw (ex-info "db-worker has not been initialized" {})))
  39. (apply worker qkw direct-pass-args? args-list)))
  40. (defn <invoke-db-worker
  41. "invoke db-worker thread api"
  42. [qkw & args]
  43. (<invoke-db-worker* qkw false args))
  44. (defn <invoke-db-worker-direct-pass-args
  45. "invoke db-worker thread api.
  46. But directly pass args to db-worker(won't do transit-write on them)."
  47. [qkw & args]
  48. (<invoke-db-worker* qkw true args))
  49. ;; Stores main application state
  50. (defonce ^:large-vars/data-var state
  51. (let [document-mode? (or (storage/get :document/mode?) false)
  52. current-graph (let [url-graph (:graph (util/parse-params))
  53. graph (or url-graph (storage/get :git/current-repo))]
  54. (when graph (ipc/ipc "setCurrentGraph" graph))
  55. graph)]
  56. (atom
  57. {:route-match nil
  58. :today nil
  59. :system/events (async/chan 1000)
  60. :file/unlinked-dirs #{}
  61. :reactive/custom-queries (async/chan 1000)
  62. :notification/show? false
  63. :notification/content nil
  64. :repo/loading-files? {}
  65. :nfs/user-granted? {}
  66. :nfs/refreshing? nil
  67. :instrument/disabled? (storage/get "instrument-disabled")
  68. ;; TODO: how to detect the network reliably?
  69. :network/online? true
  70. :indexeddb/support? true
  71. :me nil
  72. :git/current-repo current-graph
  73. :draw? false
  74. :db/restoring? nil
  75. :journals-length 3
  76. :search/q ""
  77. :search/mode nil ; nil -> global mode, :graph -> add graph filter, etc.
  78. :search/args nil
  79. :search/result nil
  80. :search/graph-filters []
  81. :search/engines {}
  82. ;; modals
  83. :modal/dropdowns {}
  84. :modal/id nil
  85. ;; ui
  86. :ui/viewport {}
  87. ;; left sidebar
  88. :ui/navigation-item-collapsed? {}
  89. :ui/recent-pages (or (storage/get :ui/recent-pages) {})
  90. ;; right sidebar
  91. :ui/handbooks-open? false
  92. :ui/help-open? false
  93. :ui/fullscreen? false
  94. :ui/settings-open? false
  95. :ui/sidebar-open? false
  96. :ui/sidebar-width "40%"
  97. :ui/left-sidebar-open? (boolean (storage/get :ls-left-sidebar-open?))
  98. :ui/theme (or (storage/get :ui/theme) "light")
  99. :ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
  100. :ui/custom-theme (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
  101. :ui/wide-mode? (storage/get :ui/wide-mode)
  102. :ui/radix-color (storage/get :ui/radix-color)
  103. :ui/editor-font (storage/get :ui/editor-font)
  104. ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
  105. ;; 1. right sidebar
  106. ;; 2. zoom-in view
  107. ;; 3. queries
  108. ;; 4. references
  109. ;; graph => {:block-id bool}
  110. :ui/collapsed-blocks {}
  111. :ui/sidebar-collapsed-blocks {}
  112. :ui/root-component nil
  113. :ui/file-component nil
  114. :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
  115. false)
  116. ;; remember scroll positions of visited paths
  117. :ui/paths-scroll-positions (atom {})
  118. :ui/main-container-scroll-top (atom nil)
  119. :ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
  120. false
  121. true)
  122. :ui/scrolling? (atom false)
  123. :ui/show-empty-and-hidden-properties? (atom {:mode :global
  124. :show? false})
  125. :document/mode? document-mode?
  126. :config {}
  127. :block/component-editing-mode? false
  128. :editor/op (atom nil)
  129. :editor/start-pos (atom nil)
  130. :editor/async-unsaved-chars (atom nil)
  131. :editor/hidden-editors #{} ;; page names
  132. :editor/draw-mode? false
  133. :editor/action (atom nil)
  134. :editor/action-data nil
  135. ;; With label or other data
  136. :editor/last-saved-cursor (atom {})
  137. :editor/editing? (atom {})
  138. :editor/in-composition? false
  139. :editor/content (atom {})
  140. :editor/block (atom nil)
  141. :editor/block-dom-id (atom nil)
  142. :editor/set-timestamp-block (atom nil) ;; click rendered block timestamp-cp to set timestamp
  143. :editor/last-input-time (atom {})
  144. :editor/document-mode? document-mode?
  145. :editor/args (atom nil)
  146. :editor/on-paste? (atom false)
  147. :editor/last-key-code (atom nil)
  148. :ui/global-last-key-code (atom nil)
  149. :editor/block-op-type nil ;; :cut, :copy
  150. :editor/block-refs (atom #{})
  151. ;; Stores deleted refed blocks, indexed by repo
  152. :editor/last-replace-ref-content-tx nil
  153. ;; for audio record
  154. :editor/record-status "NONE"
  155. :editor/code-block-context nil
  156. :editor/latest-shortcut (atom nil)
  157. :history/paused? (atom false)
  158. :editor/cursor-range (atom nil)
  159. :editor/container-id (atom nil)
  160. :editor/next-edit-block (atom nil)
  161. :editor/raw-mode-block (atom nil)
  162. :editor/virtualized-scroll-fn nil
  163. ;; Warning: blocks order is determined when setting this attribute
  164. :selection/blocks (atom [])
  165. :selection/start-block (atom nil)
  166. ;; nil, :up or :down
  167. ;; used to determine selection direction when two or more blocks are selected
  168. :selection/direction (atom nil)
  169. :selection/selected-all? (atom false)
  170. :custom-context-menu/show? false
  171. :custom-context-menu/links nil
  172. :custom-context-menu/position nil
  173. ;; pages or blocks in the right sidebar
  174. ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
  175. :sidebar/blocks '()
  176. :preferred-language (storage/get :preferred-language)
  177. ;; electron
  178. :electron/auto-updater-downloaded false
  179. :electron/updater-pending? false
  180. :electron/updater {}
  181. :electron/user-cfgs nil
  182. :electron/server nil
  183. :electron/window-maximized? false
  184. :electron/window-fullscreen? false
  185. ;; assets
  186. :assets/alias-enabled? (or (storage/get :assets/alias-enabled?) false)
  187. :assets/alias-dirs (or (storage/get :assets/alias-dirs) [])
  188. ;; mobile
  189. :mobile/container-urls nil
  190. :mobile/show-action-bar? false
  191. :mobile/actioned-block nil
  192. :mobile/show-toolbar? false
  193. :mobile/show-recording-bar? false
  194. :mobile/show-tabbar? false
  195. ;;; Used to monitor mobile app status,
  196. ;;; value spec:
  197. ;;; {:is-active? bool, :timestamp int}
  198. :mobile/app-state-change (atom nil)
  199. ;; plugin
  200. :plugin/enabled (and util/plugin-platform?
  201. ;; true false :theme-only
  202. ((fnil identity true) (storage/get ::storage-spec/lsp-core-enabled)))
  203. :plugin/preferences nil
  204. :plugin/indicator-text nil
  205. :plugin/installed-plugins {}
  206. :plugin/installed-themes []
  207. :plugin/installed-slash-commands {}
  208. :plugin/installed-ui-items {}
  209. :plugin/installed-resources {}
  210. :plugin/installed-hooks {}
  211. :plugin/installed-services {}
  212. :plugin/simple-commands {}
  213. :plugin/selected-theme nil
  214. :plugin/selected-unpacked-pkg nil
  215. :plugin/marketplace-pkgs nil
  216. :plugin/marketplace-stats nil
  217. :plugin/installing nil
  218. :plugin/active-readme nil
  219. :plugin/updates-auto-checking? false
  220. :plugin/updates-pending {}
  221. :plugin/updates-coming {}
  222. :plugin/updates-downloading? false
  223. :plugin/updates-unchecked #{}
  224. :plugin/navs-settings? true
  225. :plugin/focused-settings nil ;; plugin id
  226. ;; pdf
  227. :pdf/system-win? false
  228. :pdf/current nil
  229. :pdf/ref-highlight nil
  230. :pdf/block-highlight-colored? (or (storage/get "ls-pdf-hl-block-is-colored") true)
  231. :pdf/auto-open-ctx-menu? (not= false (storage/get "ls-pdf-auto-open-ctx-menu"))
  232. ;; all notification contents as k-v pairs
  233. :notification/contents {}
  234. :graph/syncing? false
  235. ;; graph -> state
  236. :graph/parsing-state {}
  237. :copy/export-block-text-indent-style (or (storage/get :copy/export-block-text-indent-style)
  238. "dashes")
  239. :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
  240. #{})
  241. :copy/export-block-text-other-options (or (storage/get :copy/export-block-text-other-options)
  242. {})
  243. :date-picker/date nil
  244. :youtube/players {}
  245. ;; command palette
  246. :command-palette/commands (atom [])
  247. :view/components {}
  248. :view/selected-blocks nil
  249. :srs/mode? false
  250. :srs/cards-due-count nil
  251. :reactive/query-dbs {}
  252. ;; login, userinfo, token, ...
  253. :auth/refresh-token (storage/get "refresh-token")
  254. :auth/access-token nil
  255. :auth/id-token nil
  256. ;; file-sync
  257. :file-sync/jstour-inst nil
  258. :file-sync/onboarding-state (or (storage/get :file-sync/onboarding-state)
  259. {:welcome false})
  260. :file-sync/remote-graphs {:loading false :graphs nil}
  261. :file-sync/set-remote-graph-password-result {}
  262. ;; graph-uuid -> {:graphs-txid {}
  263. ;; :file-sync/sync-manager {}
  264. ;; :file-sync/sync-state {}
  265. ;; ;; {file-path -> payload}
  266. ;; :file-sync/progress {}
  267. ;; :file-sync/start-time {}
  268. ;; :file-sync/last-synced-at {}}
  269. :file-sync/graph-state {:current-graph-uuid nil}
  270. ;; graph-uuid -> ...
  271. :rtc/state (atom {})
  272. ;; only latest rtc-log stored here, when a log stream is needed,
  273. ;; use missionary to create a rtc-log-flow, use (missionary.core/watch <atom>)
  274. :rtc/log (atom nil)
  275. :rtc/uploading? false
  276. :rtc/downloading-graph-uuid nil
  277. :rtc/graphs []
  278. :rtc/online-info (atom {})
  279. :rtc/asset-upload-download-progress (atom {})
  280. :user/info {:UserGroups (storage/get :user-groups)}
  281. :encryption/graph-parsing? false
  282. :ui/loading? {}
  283. :ui/container-id (atom 0)
  284. :ui/cached-key->container-id (atom {})
  285. :feature/enable-sync? (storage/get :logseq-sync-enabled)
  286. :feature/enable-sync-diff-merge? ((fnil identity true) (storage/get :logseq-sync-diff-merge-enabled))
  287. :feature/enable-rtc? (storage/get :logseq-rtc-enabled)
  288. :file/rename-event-chan (async/chan 100)
  289. :ui/find-in-page nil
  290. :graph/importing nil
  291. :graph/importing-state {}
  292. :graph/loading? nil
  293. :handbook/route-chan (async/chan (async/sliding-buffer 1))
  294. :whiteboard/onboarding-whiteboard? (or (storage/get :ls-onboarding-whiteboard?) false)
  295. :whiteboard/onboarding-tour? (or (storage/get :whiteboard-onboarding-tour?) false)
  296. :whiteboard/last-persisted-at {}
  297. :whiteboard/pending-tx-data {}
  298. :system/info {}
  299. ;; Whether block is selected
  300. :ui/select-query-cache (atom {})
  301. :ui/toggle-highlight-recent-blocks? (atom false)
  302. :ui/highlight-recent-days (atom (or (storage/get :ui/highlight-recent-days)
  303. 3))
  304. :favorites/updated? (atom 0)
  305. :db/async-query-loading (atom #{})
  306. :db/async-queries (atom {})
  307. :db/latest-transacted-entity-uuids (atom {})})))
  308. ;; Block ast state
  309. ;; ===============
  310. ;; block uuid -> {content(String) -> ast}
  311. (def blocks-ast-cache (atom {}))
  312. (defn add-block-ast-cache!
  313. [block-uuid content ast]
  314. (when (and block-uuid content ast)
  315. (let [new-value (assoc-in @blocks-ast-cache [block-uuid content] ast)
  316. new-value (if (> (count new-value) 10000)
  317. (into {} (take 5000 new-value))
  318. new-value)]
  319. (reset! blocks-ast-cache new-value))))
  320. (defn get-block-ast
  321. [block-uuid content]
  322. (when (and block-uuid content)
  323. (get-in @blocks-ast-cache [block-uuid content])))
  324. ;; User configuration getters under :config (and sometimes :me)
  325. ;; ========================================
  326. ;; TODO: Refactor default config values to be data driven. Currently they are all
  327. ;; buried in getters
  328. ;; TODO: Refactor our access to be more data driven. Currently each getter
  329. ;; (re-)fetches get-current-repo needlessly
  330. ;; TODO: Add consistent validation. Only a few config options validate at get time
  331. (def common-default-config
  332. "Common default config for a user's repo config"
  333. {:feature/enable-search-remove-accents? true
  334. :ui/auto-expand-block-refs? true
  335. ;; For flushing the settings of old versions. Don't bump this value.
  336. ;; There are only two kinds of graph, one is not upgraded (:legacy) and one is upgraded (:triple-lowbar)
  337. ;; For not upgraded graphs, the config will have no key `:file/name-format`
  338. ;; Then the default value is applied
  339. :file/name-format :legacy})
  340. (def file-default-config
  341. "Default repo config for file graphs"
  342. (merge common-default-config
  343. ;; The "NOW" query returns tasks with "NOW" or "DOING" status.
  344. ;; The "NEXT" query returns tasks with "NOW", "LATER", or "TODO" status.
  345. {:default-queries
  346. {:journals
  347. [{:title "🔨 NOW"
  348. :query '[:find (pull ?h [*])
  349. :in $ ?start ?today
  350. :where
  351. (task ?h #{"NOW" "DOING"})
  352. [?h :block/page ?p]
  353. [?p :block/journal-day ?d]
  354. [(>= ?d ?start)]
  355. [(<= ?d ?today)]]
  356. :inputs [:14d :today]
  357. :result-transform '(fn [result]
  358. (sort-by (fn [h]
  359. (get h :block/priority "Z")) result))
  360. :group-by-page? false
  361. :collapsed? false}
  362. {:title "📅 NEXT"
  363. :query '[:find (pull ?h [*])
  364. :in $ ?start ?next
  365. :where
  366. (task ?h #{"NOW" "LATER" "TODO"})
  367. [?h :block/page ?p]
  368. [?p :block/journal-day ?d]
  369. [(> ?d ?start)]
  370. [(< ?d ?next)]]
  371. :inputs [:today :7d-after]
  372. :group-by-page? false
  373. :collapsed? false}]}}))
  374. (def db-default-config
  375. "Default repo config for DB graphs"
  376. (merge common-default-config
  377. ;; The "DOING" query returns tasks with "Doing" status for recent past days
  378. ;; The "TODO" query returns tasks with "Todo" status for upcoming future days
  379. {:default-queries
  380. {:journals
  381. [{:title [:span (shui/tabler-icon "InProgress50" {:class "align-middle pr-1"}) [:span.align-middle "DOING"]]
  382. :query '[:find (pull ?b [*])
  383. :in $ ?start ?today
  384. :where
  385. (task ?b #{"Doing"})
  386. [?b :block/page ?p]
  387. [?p :block/journal-day ?d]
  388. [(>= ?d ?start)]
  389. [(<= ?d ?today)]]
  390. :inputs [:14d :today]
  391. :collapsed? false}
  392. {:title [:span (shui/tabler-icon "Todo" {:class "align-middle pr-1"}) [:span.align-middle "TODO"]]
  393. :query '[:find (pull ?b [*])
  394. :in $ ?start ?next
  395. :where
  396. (task ?b #{"Todo"})
  397. [?b :block/page ?p]
  398. [?p :block/journal-day ?d]
  399. [(> ?d ?start)]
  400. [(< ?d ?next)]]
  401. :inputs [:today :7d-after]
  402. :group-by-page? false
  403. :collapsed? false}]}
  404. :ui/hide-empty-properties? false}))
  405. ;; State that most user config is dependent on
  406. (declare get-current-repo sub set-state!)
  407. (defn merge-configs
  408. "Merges user configs in given orders. All values are overridden except for maps
  409. which are merged."
  410. [& configs]
  411. (->> configs
  412. (filter map?)
  413. (apply merge-with
  414. (fn merge-config [current new]
  415. (if (and (map? current) (map? new))
  416. (merge current new)
  417. new)))))
  418. (defn get-global-config
  419. []
  420. (get-in @state [:config ::global-config]))
  421. (defn get-global-config-str-content
  422. []
  423. (get-in @state [:config ::global-config-str-content]))
  424. (defn get-graph-config
  425. ([] (get-graph-config (get-current-repo)))
  426. ([repo-url] (get-in @state [:config repo-url])))
  427. (defn get-config
  428. "User config for the given repo or current repo if none given. All config fetching
  429. should be done through this fn in order to get global config and config defaults"
  430. ([]
  431. (get-config (get-current-repo)))
  432. ([repo-url]
  433. (merge-configs
  434. (if (sqlite-util/db-based-graph? repo-url) db-default-config file-default-config)
  435. (get-global-config)
  436. (get-graph-config repo-url))))
  437. (defn publishing-enable-editing?
  438. []
  439. (and common-config/PUBLISHING (:publishing/enable-editing? (get-config))))
  440. (defn enable-editing?
  441. []
  442. (or (not common-config/PUBLISHING) (:publishing/enable-editing? (get-config))))
  443. (defonce built-in-macros
  444. {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
  445. (defn get-macros
  446. []
  447. (merge
  448. built-in-macros
  449. (:macros (get-config))))
  450. (defn set-assets-alias-enabled!
  451. [v]
  452. (set-state! :assets/alias-enabled? (boolean v))
  453. (storage/set :assets/alias-enabled? (boolean v)))
  454. (defn set-assets-alias-dirs!
  455. [dirs]
  456. (when dirs
  457. (set-state! :assets/alias-dirs dirs)
  458. (storage/set :assets/alias-dirs dirs)))
  459. (defn get-custom-css-link
  460. []
  461. (:custom-css-url (get-config)))
  462. (defn get-custom-js-link
  463. []
  464. (:custom-js-url (get-config)))
  465. (defn get-default-journal-template
  466. []
  467. (when-let [template (get-in (get-config) [:default-templates :journals])]
  468. (when-not (string/blank? template)
  469. (string/trim template))))
  470. (defn all-pages-public?
  471. []
  472. (let [value (:publishing/all-pages-public? (get-config))
  473. value (if (some? value) value (:all-pages-public? (get-config)))]
  474. (true? value)))
  475. (defn get-default-home
  476. []
  477. (:default-home (get-config)))
  478. (defn custom-home-page?
  479. []
  480. (some? (:page (get-default-home))))
  481. (defn get-preferred-format
  482. ([]
  483. (get-preferred-format (get-current-repo)))
  484. ([repo-url]
  485. (keyword
  486. (or
  487. (common-config/get-preferred-format (get-config repo-url))
  488. (get-in @state [:me :preferred_format] "markdown")))))
  489. (defn markdown?
  490. []
  491. (= (keyword (get-preferred-format))
  492. :markdown))
  493. (defn get-pages-directory
  494. []
  495. (or
  496. (when-let [repo (get-current-repo)]
  497. (:pages-directory (get-config repo)))
  498. "pages"))
  499. (defn get-journals-directory
  500. []
  501. (or
  502. (when-let [repo (get-current-repo)]
  503. (:journals-directory (get-config repo)))
  504. "journals"))
  505. (defn get-whiteboards-directory
  506. []
  507. (or
  508. (when-let [repo (get-current-repo)]
  509. (:whiteboards-directory (get-config repo)))
  510. "whiteboards"))
  511. (defn org-mode-file-link?
  512. [repo]
  513. (:org-mode/insert-file-link? (get-config repo)))
  514. (defn get-journal-file-name-format
  515. []
  516. (when-let [repo (get-current-repo)]
  517. (:journal/file-name-format (get-config repo))))
  518. (defn get-preferred-workflow
  519. []
  520. (keyword
  521. (or
  522. (when-let [workflow (:preferred-workflow (get-config))]
  523. (let [workflow (name workflow)]
  524. (if (util/safe-re-find #"now|NOW" workflow)
  525. :now
  526. :todo)))
  527. (get-in @state [:me :preferred_workflow] :now))))
  528. (defn get-preferred-todo
  529. []
  530. (if (= (get-preferred-workflow) :now)
  531. "LATER"
  532. "TODO"))
  533. (defn get-filename-format
  534. ([] (get-filename-format (get-current-repo)))
  535. ([repo]
  536. (:file/name-format (get-config repo))))
  537. (defn get-date-formatter
  538. []
  539. (let [repo (get-current-repo)]
  540. (if (sqlite-util/db-based-graph? repo)
  541. (when-let [conn (db-conn-state/get-conn repo)]
  542. (get (entity-plus/entity-memoized @conn :logseq.class/Journal)
  543. :logseq.property.journal/title-format
  544. "MMM do, yyyy"))
  545. (common-config/get-date-formatter (get-config)))))
  546. (defn custom-shortcuts []
  547. (merge (storage/get :ls-shortcuts)
  548. (:shortcuts (get-config))))
  549. (defn get-commands
  550. []
  551. (:commands (get-config)))
  552. (defn get-scheduled-future-days
  553. []
  554. (let [days (:scheduled/future-days (get-config))]
  555. (or (when (int? days) days) 7)))
  556. (defn get-start-of-week
  557. []
  558. (or (:start-of-week (get-config))
  559. (get-in @state [:me :settings :start-of-week])
  560. 6))
  561. (defn get-ref-open-blocks-level
  562. []
  563. (or
  564. (when-let [value (:ref/default-open-blocks-level (get-config))]
  565. (when (integer? value)
  566. value))
  567. 2))
  568. (defn get-linked-references-collapsed-threshold
  569. []
  570. (or
  571. (when-let [value (:ref/linked-references-collapsed-threshold (get-config))]
  572. (when (integer? value)
  573. value))
  574. 100))
  575. (defn get-export-bullet-indentation
  576. []
  577. (case (get (get-config) :export/bullet-indentation :tab)
  578. :eight-spaces
  579. " "
  580. :four-spaces
  581. " "
  582. :two-spaces
  583. " "
  584. :tab
  585. "\t"))
  586. (defn enable-search-remove-accents?
  587. []
  588. (:feature/enable-search-remove-accents? (get-config)))
  589. ;; State cursor fns for use with rum components
  590. ;; ============================================
  591. (declare document-mode?)
  592. (defn sub
  593. "Creates a rum cursor, https://github.com/tonsky/rum#cursors, for use in rum components.
  594. Similar to re-frame subscriptions"
  595. [ks & {:keys [path-in-sub-atom]}]
  596. (let [ks-coll? (coll? ks)
  597. get-fn (if ks-coll? get-in get)
  598. s (get-fn @state ks)
  599. s-atom? (util/atom? s)
  600. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  601. (cond
  602. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  603. (util/react (rum/cursor-in s path-in-sub-atom))
  604. (and s-atom? path-in-sub-atom)
  605. (util/react (rum/cursor s path-in-sub-atom))
  606. s-atom? (util/react s)
  607. ks-coll? (util/react (rum/cursor-in state ks))
  608. :else (util/react (rum/cursor state ks)))))
  609. (defn set-editing-block-id!
  610. [container-block]
  611. (reset! (:editor/editing? @state) {container-block true}))
  612. (defn sub-editing?
  613. [container-block]
  614. (when container-block
  615. (rum/react
  616. (r/cached-derived-atom
  617. (:editor/editing? @state)
  618. [(get-current-repo) ::editing-block container-block]
  619. (fn [s]
  620. (get s container-block))))))
  621. (defn sub-config
  622. "Sub equivalent to get-config which should handle all sub user-config access"
  623. ([] (sub-config (get-current-repo)))
  624. ([repo]
  625. (let [config (sub :config)]
  626. (merge-configs (if (and (string? repo) (sqlite-util/db-based-graph? repo)) db-default-config file-default-config)
  627. (get config ::global-config)
  628. (get config repo)))))
  629. (defn enable-grammarly?
  630. []
  631. (true? (:feature/enable-grammarly? (sub-config))))
  632. (defn scheduled-deadlines-disabled?
  633. []
  634. (true? (:feature/disable-scheduled-and-deadline-query? (sub-config))))
  635. (defn enable-timetracking?
  636. []
  637. (not (false? (:feature/enable-timetracking? (sub-config)))))
  638. (defn enable-fold-button-right?
  639. []
  640. (let [_ (sub :ui/viewport)]
  641. (and (util/mobile?)
  642. (util/sm-breakpoint?))))
  643. (defn enable-journals?
  644. ([]
  645. (enable-journals? (get-current-repo)))
  646. ([repo]
  647. (not (false? (:feature/enable-journals? (sub-config repo))))))
  648. (defn enable-flashcards?
  649. ([]
  650. (enable-flashcards? (get-current-repo)))
  651. ([repo]
  652. (not (false? (:feature/enable-flashcards? (sub-config repo))))))
  653. (defn enable-sync?
  654. []
  655. (sub :feature/enable-sync?))
  656. (defn enable-sync-diff-merge?
  657. []
  658. (sub :feature/enable-sync-diff-merge?))
  659. (defn enable-whiteboards?
  660. ([]
  661. (enable-whiteboards? (get-current-repo)))
  662. ([repo]
  663. (not (false? (:feature/enable-whiteboards? (sub-config repo))))))
  664. (defn enable-rtc?
  665. []
  666. (sub :feature/enable-rtc?))
  667. (defn enable-git-auto-push?
  668. [repo]
  669. (not (false? (:git-auto-push (sub-config repo)))))
  670. (defn graph-settings
  671. []
  672. (:graph/settings (sub-config)))
  673. (defn graph-forcesettings
  674. []
  675. (:graph/forcesettings (sub-config)))
  676. ;; Enable by default
  677. (defn show-brackets?
  678. []
  679. (not (false? (:ui/show-brackets? (sub-config)))))
  680. (defn sub-default-home-page
  681. []
  682. (get-in (sub-config) [:default-home :page] ""))
  683. (defn- get-selected-block-ids
  684. [blocks]
  685. (->> blocks
  686. (remove nil?)
  687. (keep #(when-let [id (dom/attr % "blockid")]
  688. (uuid id)))
  689. (distinct)))
  690. (defn block-content-max-length
  691. [repo]
  692. (or (:block/title-max-length (sub-config repo))
  693. ;; backward compatible
  694. (:block/content-max-length (sub-config repo))
  695. 10000))
  696. (defn mobile?
  697. []
  698. (or (util/mobile?) (mobile-util/native-platform?)))
  699. (defn enable-tooltip?
  700. []
  701. (if (mobile?)
  702. false
  703. (get (sub-config) :ui/enable-tooltip? true)))
  704. (defn show-command-doc?
  705. []
  706. (get (sub-config) :ui/show-command-doc? true))
  707. (defn logical-outdenting?
  708. []
  709. (:editor/logical-outdenting? (sub-config)))
  710. (defn show-full-blocks?
  711. []
  712. (:ui/show-full-blocks? (sub-config)))
  713. (defn preferred-pasting-file?
  714. []
  715. (:editor/preferred-pasting-file? (sub-config)))
  716. (defn auto-expand-block-refs?
  717. []
  718. (:ui/auto-expand-block-refs? (sub-config)))
  719. (defn doc-mode-enter-for-new-line?
  720. []
  721. (and (document-mode?)
  722. (not (:shortcut/doc-mode-enter-for-new-block? (get-config)))))
  723. (defn user-groups
  724. []
  725. (set (sub [:user/info :UserGroups])))
  726. ;; State mutation helpers
  727. ;; ======================
  728. (defn set-state!
  729. [path value & {:keys [path-in-sub-atom]}]
  730. (vswap! *profile-state update path inc)
  731. (let [path-coll? (coll? path)
  732. get-fn (if path-coll? get-in get)
  733. s (get-fn @state path)
  734. s-atom? (util/atom? s)
  735. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  736. (cond
  737. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  738. (let [old-v (get-in @s path-in-sub-atom)]
  739. (when (not= old-v value)
  740. (swap! s assoc-in path-in-sub-atom value)))
  741. (and s-atom? path-in-sub-atom)
  742. (let [old-v (get @s path-in-sub-atom)]
  743. (when (not= old-v value)
  744. (swap! s assoc path-in-sub-atom value)))
  745. s-atom?
  746. (when (not= @s value)
  747. (reset! s value))
  748. path-coll?
  749. (when (not= s value)
  750. (swap! state assoc-in path value))
  751. :else
  752. (when (not= s value)
  753. (swap! state assoc path value))))
  754. nil)
  755. (defn update-state!
  756. [path f & {:keys [path-in-sub-atom]}]
  757. (vswap! *profile-state update path inc)
  758. (let [path-coll? (coll? path)
  759. get-fn (if path-coll? get-in get)
  760. s (get-fn @state path)
  761. s-atom? (util/atom? s)
  762. path-coll?-in-sub-atom (coll? path-in-sub-atom)]
  763. (cond
  764. (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
  765. (swap! s update-in path-in-sub-atom f)
  766. (and s-atom? path-in-sub-atom)
  767. (swap! s update path-in-sub-atom f)
  768. s-atom? (swap! s f)
  769. path-coll? (swap! state update-in path f)
  770. :else (swap! state update path f)))
  771. nil)
  772. ;; State getters and setters
  773. ;; =========================
  774. ;; These fns handle any key except :config.
  775. ;; Some state is also stored in local storage and/or sent to electron's main process
  776. (defn get-route-match
  777. []
  778. (:route-match @state))
  779. (defn get-current-route
  780. []
  781. (get-in (get-route-match) [:data :name]))
  782. (defn home?
  783. []
  784. (= :home (get-current-route)))
  785. (defn whiteboard-dashboard?
  786. []
  787. (= :whiteboards (get-current-route)))
  788. (defn get-current-page
  789. []
  790. (when (= :page (get-current-route))
  791. (get-in (get-route-match)
  792. [:path-params :name])))
  793. (defn route-has-p?
  794. []
  795. (get-in (get-route-match) [:query-params :p]))
  796. (defn get-current-repo
  797. "Returns the current repo URL, or else open demo graph"
  798. []
  799. (:git/current-repo @state))
  800. (defn get-remote-file-graphs
  801. []
  802. (get-in @state [:file-sync/remote-graphs :graphs]))
  803. (defn get-rtc-graphs
  804. []
  805. (:rtc/graphs @state))
  806. (defn get-remote-graph-info-by-uuid
  807. [uuid]
  808. (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
  809. (some #(when (= (:GraphUUID %) (str uuid)) %) graphs)))
  810. (defn get-remote-graph-usage
  811. []
  812. (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
  813. (->> graphs
  814. (map #(hash-map :uuid (:GraphUUID %)
  815. :name (:GraphName %)
  816. :used-gbs (/ (:GraphStorageUsage %) 1024 1024 1024)
  817. :limit-gbs (/ (:GraphStorageLimit %) 1024 1024 1024)
  818. :used-percent (/ (:GraphStorageUsage %) (:GraphStorageLimit %) 0.01)))
  819. (map #(assoc % :free-gbs (- (:limit-gbs %) (:used-gbs %))))
  820. (vec))))
  821. (defn delete-remote-graph!
  822. [repo]
  823. (let [remove-repo! (fn [repos]
  824. (remove #(and
  825. (:GraphUUID repo)
  826. (:GraphUUID %)
  827. (= (:GraphUUID repo) (:GraphUUID %))) repos))]
  828. (if (:rtc-graph? repo)
  829. (swap! state update :rtc/graphs remove-repo!)
  830. (swap! state update-in [:file-sync/remote-graphs :graphs] remove-repo!))))
  831. (defn add-remote-graph!
  832. [repo]
  833. (swap! state update-in [:file-sync/remote-graphs :graphs]
  834. (fn [repos]
  835. (->> (conj repos repo)
  836. (distinct)))))
  837. (defn get-repos
  838. []
  839. (get-in @state [:me :repos]))
  840. (defn set-repos!
  841. [repos]
  842. (set-state! [:me :repos] (distinct repos)))
  843. (defn add-repo!
  844. [repo]
  845. (when (not (string/blank? repo))
  846. (update-state! [:me :repos]
  847. (fn [repos]
  848. (->> (conj repos repo)
  849. (distinct))))))
  850. (defn set-current-repo!
  851. [repo]
  852. (swap! state assoc :git/current-repo repo)
  853. (reset! flows/*current-repo repo)
  854. (if repo
  855. (storage/set :git/current-repo repo)
  856. (storage/remove :git/current-repo))
  857. (ipc/ipc "setCurrentGraph" repo))
  858. (defn set-preferred-format!
  859. [format]
  860. (swap! state assoc-in [:me :preferred_format] (name format)))
  861. (defn set-preferred-workflow!
  862. [workflow]
  863. (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
  864. (defn set-preferred-language!
  865. [language]
  866. (set-state! :preferred-language (name language))
  867. (storage/set :preferred-language (name language)))
  868. (defn delete-repo!
  869. [repo]
  870. (swap! state update-in [:me :repos]
  871. (fn [repos]
  872. (->> (remove #(or (= (:url repo) (:url %))
  873. (and
  874. (:GraphUUID repo)
  875. (:GraphUUID %)
  876. (= (:GraphUUID repo) (:GraphUUID %)))) repos)
  877. (util/distinct-by :url)))))
  878. (defn set-timestamp-block!
  879. [value]
  880. (set-state! :editor/set-timestamp-block value))
  881. (defn get-timestamp-block
  882. []
  883. @(:editor/set-timestamp-block @state))
  884. (defn get-edit-block
  885. []
  886. @(get @state :editor/block))
  887. (defn set-edit-content!
  888. ([input-id value] (set-edit-content! input-id value true))
  889. ([input-id value set-input-value?]
  890. (when input-id
  891. (when set-input-value?
  892. (when-let [input (gdom/getElement input-id)]
  893. (util/set-change-value input value)))
  894. (set-state! :editor/content value :path-in-sub-atom
  895. (or (:block/uuid (get-edit-block)) input-id)))))
  896. (defn editing?
  897. []
  898. (seq @(:editor/editing? @state)))
  899. (defn get-edit-input-id
  900. []
  901. (when-not (exists? js/process)
  902. (when (editing?)
  903. (try
  904. (when-let [elem (or (when-let [id (:block/uuid (get-edit-block))]
  905. (gdom/getElement (str "edit-block-" id)))
  906. js/document.activeElement)]
  907. (when (util/input? elem)
  908. (let [id (gobj/get elem "id")]
  909. (when (string/starts-with? id "edit-block-")
  910. id))))
  911. (catch :default _e)))))
  912. (defn get-input
  913. []
  914. (when-let [id (get-edit-input-id)]
  915. (gdom/getElement id)))
  916. (defn get-edit-content
  917. []
  918. (when-let [id (:block/uuid (get-edit-block))]
  919. (get @(:editor/content @state) id)))
  920. (defn sub-edit-content
  921. ([]
  922. (sub-edit-content (:block/uuid (get-edit-block))))
  923. ([block-id]
  924. (when block-id
  925. (sub :editor/content {:path-in-sub-atom block-id}))))
  926. (defn set-selection-start-block!
  927. [start-block]
  928. (set-state! :selection/start-block start-block))
  929. (defn get-selection-start-block
  930. []
  931. (or @(get @state :selection/start-block)
  932. (when-let [edit-block (get-edit-block)]
  933. (let [id (str "ls-block-" (:block/uuid edit-block))]
  934. (set-selection-start-block! id)
  935. id))))
  936. (defn get-cursor-range
  937. []
  938. @(:editor/cursor-range @state))
  939. (defn set-cursor-range!
  940. [range]
  941. (set-state! :editor/cursor-range range))
  942. (defn set-search-mode!
  943. ([value] (set-search-mode! value nil))
  944. ([value args]
  945. (set-state! :search/mode value)
  946. (set-state! :search/args args)))
  947. (defn set-editor-action!
  948. [value]
  949. (set-state! :editor/action value))
  950. (defn set-editor-action-data!
  951. [value]
  952. (set-state! :editor/action-data value))
  953. (defn get-editor-action
  954. []
  955. @(:editor/action @state))
  956. (defn get-editor-action-data
  957. []
  958. (:editor/action-data @state))
  959. (defn get-editor-show-page-search?
  960. []
  961. (= (get-editor-action) :page-search))
  962. (defn get-editor-show-page-search-hashtag?
  963. []
  964. (= (get-editor-action) :page-search-hashtag))
  965. (defn get-editor-show-block-search?
  966. []
  967. (= (get-editor-action) :block-search))
  968. (defn set-editor-show-input!
  969. [value]
  970. (if value
  971. (do
  972. (set-editor-action-data! (assoc (get-editor-action-data) :options value))
  973. (set-editor-action! :input))
  974. (do
  975. (set-editor-action! nil)
  976. (set-editor-action-data! nil))))
  977. (defn get-editor-show-input
  978. []
  979. (when (= (get-editor-action) :input)
  980. (get @state :editor/action-data)))
  981. (defn set-editor-show-commands!
  982. []
  983. (when-not (get-editor-action) (set-editor-action! :commands)))
  984. (defn clear-editor-action!
  985. []
  986. (set-state! :editor/action nil))
  987. (defn get-edit-pos
  988. []
  989. (when-let [input (get-input)]
  990. (util/get-selection-start input)))
  991. (defn get-selection-direction
  992. []
  993. @(:selection/direction @state))
  994. (defn get-unsorted-selection-blocks
  995. []
  996. @(:selection/blocks @state))
  997. (defn get-selection-blocks
  998. []
  999. (let [result (get-unsorted-selection-blocks)
  1000. direction (get-selection-direction)]
  1001. (if (= direction :up)
  1002. (vec (reverse result))
  1003. result)))
  1004. (defn get-selection-block-ids
  1005. []
  1006. (get-selected-block-ids (get-selection-blocks)))
  1007. (defn sub-block-selected?
  1008. [block-id]
  1009. (assert (uuid? block-id))
  1010. (rum/react
  1011. (r/cached-derived-atom (:selection/blocks @state) [(get-current-repo) ::ui-selected block-id]
  1012. (fn [blocks] (some #{block-id} (get-selected-block-ids blocks))))))
  1013. (defn dom-clear-selection!
  1014. []
  1015. (doseq [node (dom/by-class "ls-block selected")]
  1016. (dom/remove-class! node "selected")))
  1017. (defn mark-dom-blocks-as-selected
  1018. [nodes]
  1019. (doseq [node nodes]
  1020. (dom/add-class! node "selected")))
  1021. (defn get-events-chan
  1022. []
  1023. (:system/events @state))
  1024. (defn pub-event!
  1025. {:malli/schema [:=> [:cat vector?] :any]}
  1026. [payload]
  1027. (let [d (p/deferred)
  1028. chan (get-events-chan)]
  1029. (async/put! chan [payload d])
  1030. d))
  1031. (defn- set-selection-blocks-aux!
  1032. [blocks]
  1033. (set-state! :view/selected-blocks nil)
  1034. (let [selected-ids (set (get-selected-block-ids @(:selection/blocks @state)))
  1035. _ (set-state! :selection/blocks blocks)
  1036. new-ids (set (get-selection-block-ids))
  1037. removed (set/difference selected-ids new-ids)]
  1038. (mark-dom-blocks-as-selected blocks)
  1039. (doseq [id removed]
  1040. (doseq [node (array-seq (gdom/getElementsByClass (str "id" id)))]
  1041. (dom/remove-class! node "selected")))))
  1042. (defn set-selection-blocks!
  1043. ([blocks]
  1044. (set-selection-blocks! blocks nil))
  1045. ([blocks direction]
  1046. (when (seq blocks)
  1047. (let [blocks (vec (remove nil? blocks))]
  1048. (set-selection-blocks-aux! blocks)
  1049. (when direction (set-state! :selection/direction direction))))))
  1050. (defn state-clear-selection!
  1051. []
  1052. (set-state! :selection/blocks nil)
  1053. (set-state! :selection/direction nil)
  1054. (set-state! :selection/start-block nil)
  1055. (set-state! :selection/selected-all? false)
  1056. (pub-event! [:editor/hide-action-bar]))
  1057. (defn clear-selection!
  1058. []
  1059. (dom-clear-selection!)
  1060. (state-clear-selection!))
  1061. (defn get-selection-start-block-or-first
  1062. []
  1063. (or (get-selection-start-block)
  1064. (some-> (first (get-selection-blocks))
  1065. (gobj/get "id"))))
  1066. (defn selection?
  1067. "True sense of selection mode with valid selected block"
  1068. []
  1069. (seq (get-selection-blocks)))
  1070. (defn conj-selection-block!
  1071. [block-or-blocks direction]
  1072. (let [selection-blocks (get-unsorted-selection-blocks)
  1073. block-or-blocks (if (sequential? block-or-blocks) block-or-blocks [block-or-blocks])
  1074. blocks (-> (concat selection-blocks block-or-blocks)
  1075. distinct)]
  1076. (set-selection-blocks! blocks direction)))
  1077. (defn drop-selection-block!
  1078. [block]
  1079. (set-selection-blocks-aux! (-> (remove #(= block %) (get-unsorted-selection-blocks))
  1080. vec)))
  1081. (defn drop-selection-blocks-starts-with!
  1082. [block]
  1083. (let [blocks (get-unsorted-selection-blocks)
  1084. blocks' (-> (take-while (fn [b] (not= (.-id b) (.-id block))) blocks)
  1085. vec
  1086. (conj block))]
  1087. (set-selection-blocks-aux! blocks')))
  1088. (defn drop-last-selection-block!
  1089. []
  1090. (let [blocks @(:selection/blocks @state)
  1091. blocks' (vec (butlast blocks))]
  1092. (set-selection-blocks-aux! blocks')
  1093. (last blocks)))
  1094. (defn hide-custom-context-menu!
  1095. []
  1096. (swap! state assoc
  1097. :custom-context-menu/show? false
  1098. :custom-context-menu/links nil
  1099. :custom-context-menu/position nil))
  1100. (defn toggle-navigation-item-collapsed!
  1101. [item]
  1102. (update-state! [:ui/navigation-item-collapsed? item] not))
  1103. (defn toggle-sidebar-open?!
  1104. []
  1105. (swap! state update :ui/sidebar-open? not))
  1106. (defn open-right-sidebar!
  1107. []
  1108. (swap! state assoc :ui/sidebar-open? true))
  1109. (defn hide-right-sidebar!
  1110. []
  1111. (swap! state assoc :ui/sidebar-open? false))
  1112. (defn sidebar-move-block!
  1113. [from to]
  1114. (update-state! :sidebar/blocks (fn [blocks]
  1115. (let [to (if (> from to) (inc to) to)]
  1116. (if (not= to from)
  1117. (let [item (nth blocks from)
  1118. blocks (keep-indexed #(when (not= %1 from) %2) blocks)
  1119. [l r] (split-at to blocks)]
  1120. (concat l [item] r))
  1121. blocks)))))
  1122. (defn sidebar-remove-block!
  1123. [idx]
  1124. (update-state! :sidebar/blocks (fn [blocks]
  1125. (if (string? idx)
  1126. (remove #(= (second %) idx) blocks)
  1127. (util/drop-nth idx blocks))))
  1128. (when (empty? (:sidebar/blocks @state))
  1129. (hide-right-sidebar!)))
  1130. (defn sidebar-remove-deleted-block!
  1131. [ids]
  1132. (let [ids-set (set ids)]
  1133. (update-state! :sidebar/blocks (fn [items]
  1134. (remove (fn [[repo id _]]
  1135. (and (= repo (get-current-repo)) (contains? ids-set id))) items)))
  1136. (when (empty? (:sidebar/blocks @state))
  1137. (hide-right-sidebar!))))
  1138. (defn sidebar-remove-rest!
  1139. [db-id]
  1140. (update-state! :sidebar/blocks (fn [blocks]
  1141. (remove #(not= (second %) db-id) blocks)))
  1142. (set-state! [:ui/sidebar-collapsed-blocks db-id] false))
  1143. (defn sidebar-replace-block!
  1144. [old-sidebar-key new-sidebar-key]
  1145. (update-state! :sidebar/blocks (fn [blocks]
  1146. (map #(if (= % old-sidebar-key)
  1147. new-sidebar-key
  1148. %) blocks))))
  1149. (defn sidebar-block-exists?
  1150. [idx]
  1151. (some #(= (second %) idx) (:sidebar/blocks @state)))
  1152. (defn clear-sidebar-blocks!
  1153. []
  1154. (set-state! :sidebar/blocks '()))
  1155. (defn sidebar-block-toggle-collapse!
  1156. [db-id]
  1157. (when db-id
  1158. (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
  1159. (defn sidebar-block-collapse-rest!
  1160. [db-id]
  1161. (let [items (disj (set (map second (:sidebar/blocks @state))) db-id)]
  1162. (doseq [item items] (set-state! [:ui/sidebar-collapsed-blocks item] true))))
  1163. (defn sidebar-block-set-collapsed-all!
  1164. [collapsed?]
  1165. (let [items (map second (:sidebar/blocks @state))]
  1166. (doseq [item items]
  1167. (set-state! [:ui/sidebar-collapsed-blocks item] collapsed?))))
  1168. (defn clear-editor-last-pos!
  1169. []
  1170. (set-state! :editor/last-saved-cursor {}))
  1171. (defn clear-cursor-range!
  1172. []
  1173. (set-state! :editor/cursor-range nil))
  1174. (defn clear-edit!
  1175. [& {:keys [clear-editing-block?]
  1176. :or {clear-editing-block? true}}]
  1177. (clear-editor-action!)
  1178. (when clear-editing-block?
  1179. (set-state! :editor/editing? {})
  1180. (set-state! :editor/block nil))
  1181. (set-state! :editor/start-pos nil)
  1182. (clear-editor-last-pos!)
  1183. (clear-cursor-range!)
  1184. (set-state! :editor/content {})
  1185. (set-state! :ui/select-query-cache {})
  1186. (set-state! :editor/block-refs #{})
  1187. (set-state! :editor/action-data nil)
  1188. (set-state! :view/selected-blocks nil))
  1189. (defn into-code-editor-mode!
  1190. []
  1191. (set-state! :editor/cursor-range nil)
  1192. (swap! state assoc :editor/code-mode? true))
  1193. (defn set-editor-last-pos!
  1194. [new-pos]
  1195. (update-state! :editor/last-saved-cursor
  1196. (fn [m] (assoc m (:block/uuid (get-edit-block)) new-pos))))
  1197. (defn get-editor-last-pos
  1198. []
  1199. (get @(:editor/last-saved-cursor @state) (:block/uuid (get-edit-block))))
  1200. (defn set-block-content-and-last-pos!
  1201. [edit-input-id content new-pos]
  1202. (when edit-input-id
  1203. (set-edit-content! edit-input-id content)
  1204. (set-editor-last-pos! new-pos)))
  1205. (defn set-theme-mode!
  1206. [mode]
  1207. (when (mobile-util/native-platform?)
  1208. (if (= mode "light")
  1209. (util/set-theme-light)
  1210. (util/set-theme-dark)))
  1211. (set-state! :ui/theme mode)
  1212. (storage/set :ui/theme mode))
  1213. (defn sync-system-theme!
  1214. []
  1215. (let [system-dark? (.-matches (js/window.matchMedia "(prefers-color-scheme: dark)"))]
  1216. (set-theme-mode! (if system-dark? "dark" "light"))
  1217. (set-state! :ui/system-theme? true)
  1218. (storage/set :ui/system-theme? true)))
  1219. (defn use-theme-mode!
  1220. [theme-mode]
  1221. (if (= theme-mode "system")
  1222. (sync-system-theme!)
  1223. (do
  1224. (set-theme-mode! theme-mode)
  1225. (set-state! :ui/system-theme? false)
  1226. (storage/set :ui/system-theme? false))))
  1227. (defn- toggle-theme
  1228. [theme]
  1229. (if (= theme "dark") "light" "dark"))
  1230. (defn toggle-theme!
  1231. []
  1232. (use-theme-mode! (toggle-theme (:ui/theme @state))))
  1233. (defn set-custom-theme!
  1234. ([custom-theme]
  1235. (set-custom-theme! nil custom-theme))
  1236. ([mode theme]
  1237. (set-state! (if mode [:ui/custom-theme (keyword mode)] :ui/custom-theme) theme)
  1238. (storage/set :ui/custom-theme (:ui/custom-theme @state))))
  1239. (defn restore-mobile-theme!
  1240. "Restore mobile theme setting from local storage"
  1241. []
  1242. (let [mode (or (storage/get :ui/theme) "light")
  1243. system-theme? (storage/get :ui/system-theme?)]
  1244. (when (and (not system-theme?)
  1245. (mobile-util/native-platform?))
  1246. (if (= mode "light")
  1247. (util/set-theme-light)
  1248. (util/set-theme-dark)))))
  1249. (defn set-editing-block-dom-id!
  1250. [block-dom-id]
  1251. (set-state! :editor/block-dom-id block-dom-id))
  1252. (defn get-editing-block-dom-id
  1253. []
  1254. @(:editor/block-dom-id @state))
  1255. (defn set-root-component!
  1256. [component]
  1257. (set-state! :ui/root-component component))
  1258. (defn get-root-component
  1259. []
  1260. (get @state :ui/root-component))
  1261. (defn load-app-user-cfgs
  1262. ([] (load-app-user-cfgs false))
  1263. ([refresh?]
  1264. (when (util/electron?)
  1265. (p/let [cfgs (if (or refresh? (nil? (:electron/user-cfgs @state)))
  1266. (ipc/ipc :userAppCfgs)
  1267. (:electron/user-cfgs @state))
  1268. cfgs (if (object? cfgs) (bean/->clj cfgs) cfgs)]
  1269. (set-state! :electron/user-cfgs cfgs)))))
  1270. (defn setup-electron-updater!
  1271. []
  1272. (when (util/electron?)
  1273. (js/window.apis.setUpdatesCallback
  1274. (fn [_ args]
  1275. (let [data (bean/->clj args)
  1276. pending? (not= (:type data) "completed")]
  1277. (set-state! :electron/updater-pending? pending?)
  1278. (when pending? (set-state! :electron/updater data))
  1279. nil)))))
  1280. (defn set-file-component!
  1281. [component]
  1282. (set-state! :ui/file-component component))
  1283. (defn clear-file-component!
  1284. []
  1285. (set-state! :ui/file-component nil))
  1286. (defn set-journals-length!
  1287. [value]
  1288. (when value
  1289. (set-state! :journals-length value)))
  1290. (defn save-scroll-position!
  1291. ([value]
  1292. (save-scroll-position! value js/window.location.hash))
  1293. ([value path]
  1294. (set-state! :ui/paths-scroll-positions value :path-in-sub-atom path)))
  1295. (defn save-main-container-position!
  1296. [value]
  1297. (when (not= value @(:ui/main-container-scroll-top @state))
  1298. (set-state! :ui/main-container-scroll-top value)))
  1299. (defn get-saved-scroll-position
  1300. ([]
  1301. (get-saved-scroll-position js/window.location.hash))
  1302. ([path]
  1303. (get @(get @state :ui/paths-scroll-positions) path 0)))
  1304. (defn set-today!
  1305. [value]
  1306. (set-state! :today value))
  1307. (defn get-me
  1308. []
  1309. (:me @state))
  1310. (defn set-db-restoring!
  1311. [value]
  1312. (set-state! :db/restoring? value))
  1313. (defn set-indexedb-support!
  1314. [value]
  1315. (set-state! :indexeddb/support? value))
  1316. (defn modal-opened?
  1317. []
  1318. (shui-dialog/has-modal?))
  1319. (defn close-modal! []
  1320. (shui/dialog-close!))
  1321. (defn get-reactive-custom-queries-chan
  1322. []
  1323. (:reactive/custom-queries @state))
  1324. (defn get-left-sidebar-open?
  1325. []
  1326. (get-in @state [:ui/left-sidebar-open?]))
  1327. (defn set-left-sidebar-open!
  1328. [value]
  1329. (storage/set "ls-left-sidebar-open?" (boolean value))
  1330. (set-state! :ui/left-sidebar-open? value))
  1331. (defn toggle-left-sidebar!
  1332. []
  1333. (set-left-sidebar-open!
  1334. (not (get-left-sidebar-open?))))
  1335. (defn set-developer-mode!
  1336. [value]
  1337. (set-state! :ui/developer-mode? value)
  1338. (storage/set "developer-mode" (str value)))
  1339. (defn developer-mode?
  1340. []
  1341. (:ui/developer-mode? @state))
  1342. (defn get-notification-contents
  1343. []
  1344. (get @state :notification/contents))
  1345. (defn document-mode?
  1346. []
  1347. (get @state :document/mode?))
  1348. (defn toggle-document-mode!
  1349. []
  1350. (let [mode (document-mode?)]
  1351. (set-state! :document/mode? (not mode))
  1352. (storage/set :document/mode? (not mode))))
  1353. (defn toggle-highlight-recent-blocks!
  1354. []
  1355. (let [value @(:ui/toggle-highlight-recent-blocks? @state)]
  1356. (set-state! :ui/toggle-highlight-recent-blocks? (not value))))
  1357. (defn shortcut-tooltip-enabled?
  1358. []
  1359. (get @state :ui/shortcut-tooltip?))
  1360. (defn toggle-shortcut-tooltip!
  1361. []
  1362. (let [mode (shortcut-tooltip-enabled?)]
  1363. (set-state! :ui/shortcut-tooltip? (not mode))
  1364. (storage/set :ui/shortcut-tooltip? (not mode))))
  1365. (defn set-config!
  1366. [repo-url value]
  1367. (when value (set-state! [:config repo-url] value)))
  1368. (defn set-global-config!
  1369. [value str-content]
  1370. ;; Placed under :config so cursors can work seamlessly
  1371. (when value
  1372. (set-config! ::global-config value)
  1373. (set-config! ::global-config-str-content str-content)))
  1374. (defn get-wide-mode?
  1375. []
  1376. (:ui/wide-mode? @state))
  1377. (defn toggle-wide-mode!
  1378. []
  1379. (update-state! :ui/wide-mode? not))
  1380. (defn set-online!
  1381. [value]
  1382. (set-state! :network/online? value))
  1383. (defn get-plugins-slash-commands
  1384. []
  1385. (mapcat seq (flatten (vals (:plugin/installed-slash-commands @state)))))
  1386. (defn get-plugins-commands-with-type
  1387. [type]
  1388. (->> (apply concat (vals (:plugin/simple-commands @state)))
  1389. (filterv #(= (keyword (first %)) (keyword type)))))
  1390. (defn get-plugins-ui-items-with-type
  1391. [type]
  1392. (->> (apply concat (vals (:plugin/installed-ui-items @state)))
  1393. (filterv #(= (keyword (first %)) (keyword type)))))
  1394. (defn get-plugin-resources-with-type
  1395. [pid type]
  1396. (when-let [pid (and type (keyword pid))]
  1397. (get-in @state [:plugin/installed-resources pid (keyword type)])))
  1398. (defn get-plugin-resource
  1399. [pid type key]
  1400. (when-let [resources (get-plugin-resources-with-type pid type)]
  1401. (get resources key)))
  1402. (defn upt-plugin-resource
  1403. [pid type key attr val]
  1404. (when-let [resource (get-plugin-resource pid type key)]
  1405. (let [resource (assoc resource (keyword attr) val)]
  1406. (set-state!
  1407. [:plugin/installed-resources (keyword pid) (keyword type) key] resource)
  1408. resource)))
  1409. (defn get-plugin-services
  1410. [pid type]
  1411. (when-let [installed (and pid (:plugin/installed-services @state))]
  1412. (some->> (seq (get installed (keyword pid)))
  1413. (filterv #(= type (:type %))))))
  1414. (defn install-plugin-service
  1415. ([pid type name] (install-plugin-service pid type name nil))
  1416. ([pid type name opts]
  1417. (when-let [pid (and pid type name (keyword pid))]
  1418. (let [exists (get-plugin-services pid type)]
  1419. (when-let [service (and (or (not exists) (not (some #(= name (:name %)) exists)))
  1420. {:pid pid :type type :name name :opts opts})]
  1421. (update-state! [:plugin/installed-services pid] #(conj (vec %) service))
  1422. ;; search engines state for results
  1423. (when (= type :search)
  1424. (set-state! [:search/engines (str pid name)] service)))))))
  1425. (defn uninstall-plugin-service
  1426. [pid type-or-all]
  1427. (when-let [pid (keyword pid)]
  1428. (when-let [installed (get (:plugin/installed-services @state) pid)]
  1429. (let [remove-all? (or (true? type-or-all) (nil? type-or-all))
  1430. remains (if remove-all? nil (filterv #(not= type-or-all (:type %)) installed))
  1431. removed (if remove-all? installed (filterv #(= type-or-all (:type %)) installed))]
  1432. (set-state! [:plugin/installed-services pid] remains)
  1433. ;; search engines state for results
  1434. (when-let [removed' (seq (filter #(= :search (:type %)) removed))]
  1435. (update-state! :search/engines #(apply dissoc % (mapv (fn [{:keys [pid name]}] (str pid name)) removed'))))))))
  1436. (defn get-all-plugin-services-with-type
  1437. [type]
  1438. (when-let [installed (vals (:plugin/installed-services @state))]
  1439. (mapcat (fn [s] (filter #(= (keyword type) (:type %)) s)) installed)))
  1440. (defn get-all-plugin-search-engines
  1441. []
  1442. (:search/engines @state))
  1443. (defn update-plugin-search-engine
  1444. [pid name f]
  1445. (when-let [pid (keyword pid)]
  1446. (set-state! :search/engines
  1447. (update-vals (get-all-plugin-search-engines)
  1448. #(if (and (= pid (:pid %)) (= name (:name %)))
  1449. (f %) %)))))
  1450. (defn reset-plugin-search-engines
  1451. []
  1452. (when-let [engines (get-all-plugin-search-engines)]
  1453. (set-state! :search/engines
  1454. (update-vals engines #(assoc % :result nil)))))
  1455. (defn install-plugin-hook
  1456. ([pid hook] (install-plugin-hook pid hook true))
  1457. ([pid hook opts]
  1458. (when-let [pid (keyword pid)]
  1459. (set-state!
  1460. [:plugin/installed-hooks hook]
  1461. (assoc
  1462. ((fnil identity {}) (get-in @state [:plugin/installed-hooks hook]))
  1463. pid opts)) true)))
  1464. (defn uninstall-plugin-hook
  1465. [pid hook-or-all]
  1466. (when-let [pid (keyword pid)]
  1467. (if (nil? hook-or-all)
  1468. (swap! state update :plugin/installed-hooks #(update-vals % (fn [ids] (dissoc ids pid))))
  1469. (when-let [coll (get-in @state [:plugin/installed-hooks hook-or-all])]
  1470. (set-state! [:plugin/installed-hooks hook-or-all] (dissoc coll pid))))
  1471. true))
  1472. (defn slot-hook-exist?
  1473. [uuid]
  1474. (when-let [type (and uuid (string/replace (str uuid) "-" "_"))]
  1475. (when-let [hooks (sub :plugin/installed-hooks)]
  1476. (contains? hooks (str "hook:editor:slot_" type)))))
  1477. (defn active-tldraw-app
  1478. []
  1479. (when-let [tldraw-el (.querySelector js/document.body ".logseq-tldraw[data-tlapp]")]
  1480. (gobj/get js/window.tlapps (.. tldraw-el -dataset -tlapp))))
  1481. (defn tldraw-editing-logseq-block?
  1482. []
  1483. (when-let [app (active-tldraw-app)]
  1484. (and (= 1 (.. app -selectedShapesArray -length))
  1485. (= (.. app -editingShape) (.. app -selectedShapesArray (at 0))))))
  1486. (defn set-graph-syncing?
  1487. [value]
  1488. (set-state! :graph/syncing? value))
  1489. (defn set-editor-in-composition!
  1490. [value]
  1491. (set-state! :editor/in-composition? value))
  1492. (defn editor-in-composition?
  1493. []
  1494. (:editor/in-composition? @state))
  1495. (defn set-loading-files!
  1496. [repo value]
  1497. (when repo
  1498. (set-state! [:repo/loading-files? repo] value)))
  1499. (defn loading-files?
  1500. [repo]
  1501. (get-in @state [:repo/loading-files? repo]))
  1502. (defn set-editor-last-input-time!
  1503. [repo time]
  1504. (set-state! :editor/last-input-time time :path-in-sub-atom repo))
  1505. (defn input-idle?
  1506. [repo & {:keys [diff]
  1507. :or {diff 1000}}]
  1508. (when repo
  1509. (let [last-input-time (get @(get @state :editor/last-input-time) repo)]
  1510. (or
  1511. (nil? last-input-time)
  1512. (let [now (util/time-ms)]
  1513. (>= (- now last-input-time) diff))
  1514. ;; not in editing mode
  1515. ;; Is this a good idea to put whiteboard check here?
  1516. (not (get-edit-input-id))))))
  1517. (defn set-nfs-refreshing!
  1518. [value]
  1519. (set-state! :nfs/refreshing? value))
  1520. (defn nfs-refreshing?
  1521. []
  1522. (:nfs/refreshing? @state))
  1523. (defn set-search-result!
  1524. [value]
  1525. (set-state! :search/result value))
  1526. (defn clear-search-result!
  1527. []
  1528. (set-search-result! nil))
  1529. (defn add-graph-search-filter!
  1530. [q]
  1531. (when-not (string/blank? q)
  1532. (update-state! :search/graph-filters
  1533. (fn [value]
  1534. (vec (distinct (conj value q)))))))
  1535. (defn remove-search-filter!
  1536. [q]
  1537. (when-not (string/blank? q)
  1538. (update-state! :search/graph-filters
  1539. (fn [value]
  1540. (remove #{q} value)))))
  1541. (defn clear-search-filters!
  1542. []
  1543. (set-state! :search/graph-filters []))
  1544. (defn get-search-mode
  1545. []
  1546. (:search/mode @state))
  1547. (defn toggle!
  1548. [path]
  1549. (update-state! path not))
  1550. (defn toggle-settings!
  1551. []
  1552. (toggle! :ui/settings-open?))
  1553. (defn settings-open?
  1554. []
  1555. (:ui/settings-open? @state))
  1556. (defn close-settings!
  1557. []
  1558. (set-state! :ui/settings-open? false))
  1559. (defn open-settings!
  1560. ([] (open-settings! true))
  1561. ([active-tab] (set-state! :ui/settings-open? active-tab)))
  1562. (defn sidebar-add-block!
  1563. [repo db-id block-type]
  1564. (when (not (util/sm-breakpoint?))
  1565. (let [page (and (sqlite-util/db-based-graph? repo)
  1566. (= :page block-type)
  1567. (some-> (db-conn-state/get-conn repo) deref (d/entity db-id)))]
  1568. (if (and page
  1569. ;; TODO: Use config/dev? when it's not a circular dep
  1570. (not goog.DEBUG)
  1571. (or (ldb/hidden? page)
  1572. (and (ldb/built-in? page) (ldb/private-built-in-page? page))))
  1573. (pub-event! [:notification/show {:content "Cannot open an internal page." :status :warning}])
  1574. (when db-id
  1575. (update-state! :sidebar/blocks (fn [blocks]
  1576. (->> (remove #(= (second %) db-id) blocks)
  1577. (cons [repo db-id block-type])
  1578. (distinct))))
  1579. (set-state! [:ui/sidebar-collapsed-blocks db-id] false)
  1580. (open-right-sidebar!)
  1581. (when-let [elem (gdom/getElementByClass "sidebar-item-list")]
  1582. (util/scroll-to elem 0)))))))
  1583. (defn get-export-block-text-indent-style []
  1584. (:copy/export-block-text-indent-style @state))
  1585. (defn set-export-block-text-indent-style!
  1586. [v]
  1587. (set-state! :copy/export-block-text-indent-style v)
  1588. (storage/set :copy/export-block-text-indent-style v))
  1589. (defn get-recent-pages
  1590. []
  1591. (get-in @state [:ui/recent-pages (get-current-repo)]))
  1592. (defn set-recent-pages!
  1593. [v]
  1594. (set-state! [:ui/recent-pages (get-current-repo)] v)
  1595. (storage/set :ui/recent-pages (:ui/recent-pages @state)))
  1596. (defn get-export-block-text-remove-options []
  1597. (:copy/export-block-text-remove-options @state))
  1598. (defn update-export-block-text-remove-options!
  1599. [e k]
  1600. (let [f (if (util/echecked? e) conj disj)]
  1601. (update-state! :copy/export-block-text-remove-options
  1602. #(f % k))
  1603. (storage/set :copy/export-block-text-remove-options
  1604. (get-export-block-text-remove-options))))
  1605. (defn get-export-block-text-other-options []
  1606. (:copy/export-block-text-other-options @state))
  1607. (defn update-export-block-text-other-options!
  1608. [k v]
  1609. (update-state! :copy/export-block-text-other-options #(assoc % k v)))
  1610. (defn set-editor-args!
  1611. [args]
  1612. (set-state! :editor/args args))
  1613. (defn editing-whiteboard-portal?
  1614. []
  1615. (and (active-tldraw-app) (tldraw-editing-logseq-block?)))
  1616. (defn block-component-editing?
  1617. []
  1618. (and (:block/component-editing-mode? @state)
  1619. (not (editing-whiteboard-portal?))))
  1620. (defn set-block-component-editing-mode!
  1621. [value]
  1622. (set-state! :block/component-editing-mode? value))
  1623. (defn get-editor-args
  1624. []
  1625. @(:editor/args @state))
  1626. (defn set-page-blocks-cp!
  1627. [value]
  1628. (set-state! [:view/components :page-blocks] value))
  1629. (defn get-page-blocks-cp
  1630. []
  1631. (get-in @state [:view/components :page-blocks]))
  1632. ;; To avoid circular dependencies
  1633. (defn set-component!
  1634. [k value]
  1635. (set-state! [:view/components k] value))
  1636. (defn get-component
  1637. [k]
  1638. (get-in @state [:view/components k]))
  1639. (defn exit-editing-and-set-selected-blocks!
  1640. ([blocks]
  1641. (exit-editing-and-set-selected-blocks! blocks nil))
  1642. ([blocks direction]
  1643. (clear-edit!)
  1644. (set-selection-blocks! blocks direction)))
  1645. (defn set-editing!
  1646. [edit-input-id content block cursor-range & {:keys [db move-cursor? container-id property-block direction event pos]
  1647. :or {move-cursor? true}}]
  1648. (when-not (exists? js/process)
  1649. (if (> (count content)
  1650. (block-content-max-length (get-current-repo)))
  1651. (let [elements (array-seq (js/document.getElementsByClassName (str "id" (:block/uuid block))))]
  1652. (when (first elements)
  1653. (util/scroll-to-element (gobj/get (first elements) "id")))
  1654. (exit-editing-and-set-selected-blocks! elements))
  1655. (when (and edit-input-id block
  1656. (or
  1657. (publishing-enable-editing?)
  1658. (not common-config/PUBLISHING)))
  1659. (let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
  1660. container (util/get-block-container block-element)
  1661. block (if container
  1662. (assoc block
  1663. :block.temp/container (gobj/get container "id"))
  1664. block)
  1665. block (assoc block :block.editing/direction direction
  1666. :block.editing/event event
  1667. :block.editing/pos pos)
  1668. content (string/trim (or content ""))]
  1669. (assert (and container-id (:block/uuid block))
  1670. "container-id or block uuid is missing")
  1671. (set-state! :editor/block-refs #{})
  1672. (if property-block
  1673. (set-editing-block-id! [container-id (:block/uuid property-block) (:block/uuid block)])
  1674. (set-editing-block-id! [container-id (:block/uuid block)]))
  1675. (set-state! :editor/container-id container-id)
  1676. (set-state! :editor/block block)
  1677. (set-state! :editor/content content :path-in-sub-atom (:block/uuid block))
  1678. (set-state! :editor/last-key-code nil)
  1679. (set-state! :editor/set-timestamp-block nil)
  1680. (set-state! :editor/cursor-range cursor-range)
  1681. (when (= :code (:logseq.property.node/display-type (d/entity db (:db/id block))))
  1682. (pub-event! [:editor/focus-code-editor block block-element]))
  1683. (when-let [input (gdom/getElement edit-input-id)]
  1684. (let [pos (count cursor-range)]
  1685. (when content
  1686. (util/set-change-value input content))
  1687. (when (and move-cursor? (not (block-component-editing?)))
  1688. (cursor/move-cursor-to input pos))
  1689. (when (or (util/mobile?) (mobile-util/native-platform?))
  1690. (set-state! :mobile/show-action-bar? false)))))))))
  1691. (defn action-bar-open?
  1692. []
  1693. (:mobile/show-action-bar? @state))
  1694. (defn get-git-auto-commit-enabled?
  1695. []
  1696. (false? (sub [:electron/user-cfgs :git/disable-auto-commit?])))
  1697. (defn get-git-commit-on-close-enabled?
  1698. []
  1699. (sub [:electron/user-cfgs :git/commit-on-close?]))
  1700. (defn set-last-key-code!
  1701. [key-code]
  1702. (set-state! :editor/last-key-code key-code))
  1703. (defn get-last-key-code
  1704. []
  1705. @(:editor/last-key-code @state))
  1706. (defn set-ui-last-key-code!
  1707. [key-code]
  1708. (set-state! :ui/global-last-key-code key-code))
  1709. (defn get-ui-last-key-code
  1710. []
  1711. @(:ui/global-last-key-code @state))
  1712. (defn set-block-op-type!
  1713. [op-type]
  1714. (set-state! :editor/block-op-type op-type))
  1715. (defn get-block-op-type
  1716. []
  1717. (:editor/block-op-type @state))
  1718. (defn feature-http-server-enabled?
  1719. []
  1720. (boolean (storage/get ::storage-spec/http-server-enabled)))
  1721. (defn get-plugin-by-id
  1722. [id]
  1723. (when-let [id (and id (keyword id))]
  1724. (get-in @state [:plugin/installed-plugins id])))
  1725. (defn get-enabled?-installed-plugins
  1726. ([theme?] (get-enabled?-installed-plugins theme? true false false))
  1727. ([theme? enabled? include-unpacked? include-all?]
  1728. (filterv
  1729. #(and (if include-unpacked? true (or (:webMode %) (:iir %)))
  1730. (if-not (boolean? enabled?) true (= (not enabled?) (boolean (get-in % [:settings :disabled]))))
  1731. (or include-all? (if (boolean? theme?) (= (boolean theme?) (:theme %)) true)))
  1732. (vals (:plugin/installed-plugins @state)))))
  1733. (defn lsp-enabled?-or-theme
  1734. []
  1735. (:plugin/enabled @state))
  1736. (def lsp-enabled?
  1737. (lsp-enabled?-or-theme))
  1738. (defn consume-updates-from-coming-plugin!
  1739. [payload updated?]
  1740. (when-let [id (keyword (:id payload))]
  1741. (let [prev-pending? (boolean (seq (:plugin/updates-pending @state)))]
  1742. (println "Updates: consumed pending - " id)
  1743. (swap! state update :plugin/updates-pending dissoc id)
  1744. (if updated?
  1745. (if-let [error (:error-code payload)]
  1746. (swap! state update-in [:plugin/updates-coming id] assoc :error-code error)
  1747. (swap! state update :plugin/updates-coming dissoc id))
  1748. (swap! state update :plugin/updates-coming assoc id payload))
  1749. (pub-event! [:plugin/consume-updates id prev-pending? updated?]))))
  1750. (defn coming-update-new-version?
  1751. [pkg]
  1752. (and pkg (:latest-version pkg)))
  1753. (defn plugin-update-available?
  1754. [id]
  1755. (when-let [pkg (and id (get (:plugin/updates-coming @state) (keyword id)))]
  1756. (coming-update-new-version? pkg)))
  1757. (defn all-available-coming-updates
  1758. ([] (all-available-coming-updates (:plugin/updates-coming @state)))
  1759. ([updates] (when-let [updates (vals updates)]
  1760. (filterv #(coming-update-new-version? %) updates))))
  1761. (defn get-next-selected-coming-update
  1762. []
  1763. (when-let [updates (all-available-coming-updates)]
  1764. (let [unchecked (:plugin/updates-unchecked @state)]
  1765. (first (filter #(and (not (and (seq unchecked) (contains? unchecked (:id %))))
  1766. (not (:error-code %))) updates)))))
  1767. (defn set-unchecked-update
  1768. [id unchecked?]
  1769. (swap! state update :plugin/updates-unchecked (if unchecked? conj disj) id))
  1770. (defn reset-unchecked-update
  1771. []
  1772. (swap! state assoc :plugin/updates-unchecked #{}))
  1773. (defn reset-all-updates-state
  1774. []
  1775. (swap! state assoc
  1776. :plugin/updates-auto-checking? false
  1777. :plugin/updates-pending {}
  1778. :plugin/updates-coming {}
  1779. :plugin/updates-downloading? false))
  1780. (defn sub-right-sidebar-blocks
  1781. []
  1782. (when-let [current-repo (get-current-repo)]
  1783. (->> (sub :sidebar/blocks)
  1784. (filter #(= (first %) current-repo)))))
  1785. (defn toggle-collapsed-block!
  1786. [block-id]
  1787. (let [current-repo (get-current-repo)]
  1788. (update-state! [:ui/collapsed-blocks current-repo block-id] not)))
  1789. (defn set-collapsed-block!
  1790. [block-id value]
  1791. (let [current-repo (get-current-repo)]
  1792. (set-state! [:ui/collapsed-blocks current-repo block-id] value)))
  1793. (defn sub-block-collapsed
  1794. [block-id]
  1795. (sub [:ui/collapsed-blocks (get-current-repo) block-id]))
  1796. (defn get-block-collapsed
  1797. [block-id]
  1798. (get-in @state [:ui/collapsed-blocks (get-current-repo) block-id]))
  1799. (defn get-modal-id
  1800. []
  1801. (shui-dialog/get-last-modal-id))
  1802. (defn set-auth-id-token
  1803. [id-token]
  1804. (set-state! :auth/id-token id-token))
  1805. (defn set-auth-refresh-token
  1806. [refresh-token]
  1807. (set-state! :auth/refresh-token refresh-token))
  1808. (defn set-auth-access-token
  1809. [access-token]
  1810. (set-state! :auth/access-token access-token))
  1811. (defn get-auth-id-token []
  1812. (sub :auth/id-token))
  1813. (defn get-auth-refresh-token []
  1814. (:auth/refresh-token @state))
  1815. (defn set-file-sync-manager [graph-uuid v]
  1816. (when (and graph-uuid v)
  1817. (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-manager] v)))
  1818. (defn get-file-sync-manager [graph-uuid]
  1819. (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-manager]))
  1820. (defn clear-file-sync-state! [graph-uuid]
  1821. (set-state! [:file-sync/graph-state graph-uuid] nil))
  1822. (defn clear-file-sync-progress! [graph-uuid]
  1823. (set-state! [:file-sync/graph-state
  1824. graph-uuid
  1825. :file-sync/progress]
  1826. nil))
  1827. (defn set-file-sync-state [graph-uuid v]
  1828. (when v (s/assert :frontend.fs.sync/sync-state v))
  1829. (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-state] v))
  1830. (defn get-current-file-sync-graph-uuid
  1831. []
  1832. (get-in @state [:file-sync/graph-state :current-graph-uuid]))
  1833. (defn sub-current-file-sync-graph-uuid
  1834. []
  1835. (sub [:file-sync/graph-state :current-graph-uuid]))
  1836. (defn get-file-sync-state
  1837. ([]
  1838. (get-file-sync-state (get-current-file-sync-graph-uuid)))
  1839. ([graph-uuid]
  1840. (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-state])))
  1841. (defn sub-file-sync-state
  1842. [graph-uuid]
  1843. (sub [:file-sync/graph-state graph-uuid :file-sync/sync-state]))
  1844. (defn reset-parsing-state!
  1845. []
  1846. (set-state! [:graph/parsing-state (get-current-repo)] {}))
  1847. (defn set-parsing-state!
  1848. [m]
  1849. (update-state! [:graph/parsing-state (get-current-repo)]
  1850. (if (fn? m) m
  1851. (fn [old-value] (merge old-value m)))))
  1852. (defn http-proxy-enabled-or-val? []
  1853. (when-let [{:keys [type protocol host port] :as agent-opts} (sub [:electron/user-cfgs :settings/agent])]
  1854. (when (and (not (contains? #{"system"} type))
  1855. (every? not-empty (vals agent-opts)))
  1856. (str protocol "://" host ":" port))))
  1857. (defn set-mobile-app-state-change
  1858. [is-active?]
  1859. (set-state! :mobile/app-state-change
  1860. {:is-active? is-active?
  1861. :timestamp (inst-ms (js/Date.))}))
  1862. (defn get-sync-graph-by-id
  1863. [graph-uuid]
  1864. (when graph-uuid
  1865. (let [graph (first (filter #(= graph-uuid (:GraphUUID %))
  1866. (get-repos)))]
  1867. (when (:url graph)
  1868. graph))))
  1869. (defn unlinked-dir?
  1870. [dir]
  1871. (contains? (:file/unlinked-dirs @state) dir))
  1872. (defn get-file-rename-event-chan
  1873. []
  1874. (:file/rename-event-chan @state))
  1875. (defn offer-file-rename-event-chan!
  1876. [v]
  1877. {:pre [(map? v)
  1878. (= #{:repo :old-path :new-path} (set (keys v)))]}
  1879. (async/offer! (get-file-rename-event-chan) v))
  1880. (defn set-onboarding-whiteboard!
  1881. [v]
  1882. (set-state! :whiteboard/onboarding-whiteboard? v)
  1883. (storage/set :ls-onboarding-whiteboard? v))
  1884. (defn get-onboarding-whiteboard?
  1885. []
  1886. (get-in @state [:whiteboard/onboarding-whiteboard?]))
  1887. (defn get-local-container-root-url
  1888. []
  1889. (when (mobile-util/native-ios?)
  1890. (get-in @state [:mobile/container-urls :localContainerUrl])))
  1891. (defn get-icloud-container-root-url
  1892. []
  1893. (when (mobile-util/native-ios?)
  1894. (get-in @state [:mobile/container-urls :iCloudContainerUrl])))
  1895. (defn get-current-pdf
  1896. []
  1897. (:pdf/current @state))
  1898. (defn nfs-user-granted?
  1899. [repo]
  1900. (get-in @state [:nfs/user-granted? repo]))
  1901. (defn set-current-pdf!
  1902. [inflated-file]
  1903. (let [settle-file! #(set-state! :pdf/current inflated-file)]
  1904. (if-not (get-current-pdf)
  1905. (settle-file!)
  1906. (when (apply not= (map :identity [inflated-file (get-current-pdf)]))
  1907. (set-state! :pdf/current nil)
  1908. (js/setTimeout #(settle-file!) 16)))))
  1909. (defn focus-whiteboard-shape
  1910. ([shape-id]
  1911. (focus-whiteboard-shape (active-tldraw-app) shape-id))
  1912. ([tln shape-id]
  1913. (when-let [^js api (gobj/get tln "api")]
  1914. (when (and shape-id (parse-uuid shape-id))
  1915. (. api selectShapes shape-id)
  1916. (. api zoomToSelection)))))
  1917. (defn set-user-info!
  1918. [info]
  1919. (when info
  1920. (set-state! :user/info info)
  1921. (let [groups (:UserGroups info)]
  1922. (when (seq groups)
  1923. (storage/set :user-groups groups)))))
  1924. (defn get-user-info []
  1925. (sub :user/info))
  1926. (defn clear-user-info!
  1927. []
  1928. (storage/remove :user-groups))
  1929. (defn sub-async-query-loading
  1930. [k]
  1931. (assert (or (string? k) (uuid? k)))
  1932. (let [k* (str k)]
  1933. (rum/react
  1934. (r/cached-derived-atom (:db/async-query-loading @state) [(get-current-repo) ::async-query k*]
  1935. (fn [s] (contains? s k*))))))
  1936. (defn clear-async-query-state!
  1937. []
  1938. (reset! (:db/async-query-loading @state) #{}))
  1939. (defn set-color-accent! [color]
  1940. (swap! state assoc :ui/radix-color color)
  1941. (storage/set :ui/radix-color color)
  1942. (util/set-android-theme))
  1943. (defn set-editor-font! [font]
  1944. (let [font (if (keyword? font) (name font) (str font))]
  1945. (swap! state assoc :ui/editor-font font)
  1946. (storage/set :ui/editor-font font)))
  1947. (defn handbook-open?
  1948. []
  1949. (:ui/handbooks-open? @state))
  1950. (defn get-handbook-route-chan
  1951. []
  1952. (:handbook/route-chan @state))
  1953. (defn open-handbook-pane!
  1954. [k]
  1955. (when-not (handbook-open?)
  1956. (set-state! :ui/handbooks-open? true))
  1957. (js/setTimeout #(async/go
  1958. (>! (get-handbook-route-chan) k))))
  1959. (defn update-favorites-updated!
  1960. []
  1961. (update-state! :favorites/updated? inc))
  1962. (def get-worker-next-request-id db-transact/get-next-request-id)
  1963. (def add-worker-request! db-transact/add-request!)
  1964. (defn get-next-container-id
  1965. []
  1966. (swap! (:ui/container-id @state) inc))
  1967. (defn get-container-id
  1968. "Either cached container-id or a new id"
  1969. [key]
  1970. (if (seq key)
  1971. (or (get @(:ui/cached-key->container-id @state) key)
  1972. (let [id (get-next-container-id)]
  1973. (swap! (:ui/cached-key->container-id @state) assoc key id)
  1974. id))
  1975. (get-next-container-id)))
  1976. (defn get-current-editor-container-id
  1977. []
  1978. @(:editor/container-id @state))
  1979. (comment
  1980. (defn remove-container-key!
  1981. [key]
  1982. (swap! (:ui/cached-key->container-id @state) dissoc key)))
  1983. (defn get-editor-info
  1984. []
  1985. (when-let [edit-block (get-edit-block)]
  1986. {:block-uuid (:block/uuid edit-block)
  1987. :container-id (or @(:editor/container-id @state) :unknown-container)
  1988. :start-pos @(:editor/start-pos @state)
  1989. :end-pos (get-edit-pos)}))
  1990. (defn conj-block-ref!
  1991. [ref-entity]
  1992. (let [refs! (:editor/block-refs @state)]
  1993. (swap! refs! conj ref-entity)))
  1994. (defn get-highlight-recent-days
  1995. []
  1996. @(:ui/highlight-recent-days @state))
  1997. (defn set-highlight-recent-days!
  1998. [days]
  1999. (prn :debug :set :days days)
  2000. (reset! (:ui/highlight-recent-days @state) days)
  2001. (storage/set :ui/highlight-recent-days days))
  2002. (defn set-rtc-enabled!
  2003. [value]
  2004. (storage/set :logseq-rtc-enabled value)
  2005. (set-state! :feature/enable-rtc? value))