| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397 |
- (ns frontend.state
- "Provides main application state, fns associated to set and state based rum
- cursors"
- (:require [cljs-bean.core :as bean]
- [cljs.core.async :as async :refer [>!]]
- [cljs.spec.alpha :as s]
- [clojure.set :as set]
- [clojure.string :as string]
- [datascript.core :as d]
- [dommy.core :as dom]
- [electron.ipc :as ipc]
- [frontend.db.conn-state :as db-conn-state]
- [frontend.db.transact :as db-transact]
- [frontend.flows :as flows]
- [frontend.mobile.util :as mobile-util]
- [frontend.spec.storage :as storage-spec]
- [frontend.storage :as storage]
- [frontend.util :as util]
- [frontend.util.cursor :as cursor]
- [goog.dom :as gdom]
- [goog.object :as gobj]
- [logseq.common.config :as common-config]
- [logseq.db :as ldb]
- [logseq.db.common.entity-plus :as entity-plus]
- [logseq.db.sqlite.util :as sqlite-util]
- [logseq.shui.dialog.core :as shui-dialog]
- [logseq.shui.hooks :as hooks]
- [logseq.shui.ui :as shui]
- [missionary.core :as m]
- [promesa.core :as p]
- [rum.core :as rum]))
- (defonce *profile-state (volatile! {}))
- (defonce *db-worker (atom nil))
- (defonce *editor-info (atom nil))
- (defn- <invoke-db-worker*
- [qkw direct-pass-args? args-list]
- (let [worker @*db-worker]
- (when (nil? worker)
- (prn :<invoke-db-worker-error qkw)
- (throw (ex-info "db-worker has not been initialized" {})))
- (apply worker qkw direct-pass-args? args-list)))
- (defn <invoke-db-worker
- "invoke db-worker thread api"
- [qkw & args]
- (<invoke-db-worker* qkw false args))
- (defn <invoke-db-worker-direct-pass-args
- "invoke db-worker thread api.
- But directly pass args to db-worker(won't do transit-write on them)."
- [qkw & args]
- (<invoke-db-worker* qkw true args))
- ;; Stores main application state
- (defonce ^:large-vars/data-var state
- (let [document-mode? (or (storage/get :document/mode?) false)
- current-graph (let [url-graph (:graph (util/parse-params))
- graph (or url-graph (storage/get :git/current-repo))]
- (when graph (ipc/ipc "setCurrentGraph" graph))
- graph)]
- (atom
- {:client-id (str (random-uuid))
- :route-match nil
- :today nil
- :system/events (async/chan 1000)
- :file/unlinked-dirs #{}
- :reactive/custom-queries (async/chan 1000)
- :notification/show? false
- :notification/content nil
- :repo/loading-files? {}
- :nfs/user-granted? {}
- :nfs/refreshing? nil
- :instrument/disabled? (storage/get "instrument-disabled")
- ;; TODO: how to detect the network reliably?
- ;; NOTE: prefer to use flows/network-online-event-flow
- :network/online? true
- :indexeddb/support? true
- :me nil
- :git/current-repo current-graph
- :draw? false
- :db/restoring? nil
- :search/q ""
- :search/mode nil ; nil -> global mode, :graph -> add graph filter, etc.
- :search/args nil
- :search/result nil
- :search/graph-filters []
- :search/engines {}
- ;; modals
- :modal/dropdowns {}
- :modal/id nil
- ;; ui
- :ui/viewport {}
- ;; left sidebar
- :ui/navigation-item-collapsed? {}
- :ui/recent-pages (or (storage/get :ui/recent-pages) {})
- ;; right sidebar
- :ui/handbooks-open? false
- :ui/help-open? false
- :ui/fullscreen? false
- :ui/settings-open? false
- :ui/sidebar-open? false
- :ui/sidebar-width "40%"
- :ui/left-sidebar-open? (boolean (storage/get :ls-left-sidebar-open?))
- :ui/theme (or (storage/get :ui/theme) "light")
- :ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
- :ui/custom-theme (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
- :ui/wide-mode? (storage/get :ui/wide-mode)
- :ui/radix-color (storage/get :ui/radix-color)
- :ui/editor-font (storage/get :ui/editor-font)
- ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
- ;; 1. right sidebar
- ;; 2. zoom-in view
- ;; 3. queries
- ;; 4. references
- ;; graph => {:block-id bool}
- :ui/collapsed-blocks {}
- :ui/sidebar-collapsed-blocks {}
- :ui/root-component nil
- :ui/file-component nil
- :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
- false)
- ;; remember scroll positions of visited paths
- :ui/paths-scroll-positions (atom {})
- :ui/main-container-scroll-top (atom nil)
- :ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
- false
- true)
- :ui/scrolling? (atom false)
- :ui/show-empty-and-hidden-properties? (atom {:mode :global
- :show? false})
- :document/mode? document-mode?
- :config {}
- :block/component-editing-mode? false
- :editor/op (atom nil)
- :editor/start-pos (atom nil)
- :editor/async-unsaved-chars (atom nil)
- :editor/hidden-editors #{} ;; page names
- :editor/draw-mode? false
- :editor/action (atom nil)
- :editor/action-data nil
- ;; With label or other data
- :editor/last-saved-cursor (atom {})
- :editor/editing? (atom {})
- :editor/in-composition? false
- :editor/content (atom {})
- :editor/block (atom nil)
- :editor/block-dom-id (atom nil)
- :editor/set-timestamp-block (atom nil) ;; click rendered block timestamp-cp to set timestamp
- :editor/last-input-time (atom {})
- :editor/document-mode? document-mode?
- :editor/args (atom nil)
- :editor/on-paste? (atom false)
- :editor/last-key-code (atom nil)
- :ui/global-last-key-code (atom nil)
- :editor/block-op-type nil ;; :cut, :copy
- :editor/block-refs (atom #{})
- ;; Stores deleted refed blocks, indexed by repo
- :editor/last-replace-ref-content-tx nil
- ;; for audio record
- :editor/record-status "NONE"
- :editor/code-block-context nil
- :editor/latest-shortcut (atom nil)
- :history/paused? (atom false)
- :editor/cursor-range (atom nil)
- :editor/container-id (atom nil)
- :editor/next-edit-block (atom nil)
- :editor/raw-mode-block (atom nil)
- :editor/virtualized-scroll-fn nil
- ;; Warning: blocks order is determined when setting this attribute
- :selection/blocks (atom [])
- :selection/start-block (atom nil)
- ;; nil, :up or :down
- ;; used to determine selection direction when two or more blocks are selected
- :selection/direction (atom nil)
- :selection/selected-all? (atom false)
- :custom-context-menu/show? false
- :custom-context-menu/links nil
- :custom-context-menu/position nil
- ;; pages or blocks in the right sidebar
- ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
- :sidebar/blocks '()
- :preferred-language (storage/get :preferred-language)
- ;; electron
- :electron/auto-updater-downloaded false
- :electron/updater-pending? false
- :electron/updater {}
- :electron/user-cfgs nil
- :electron/server nil
- :electron/window-maximized? false
- :electron/window-fullscreen? false
- ;; assets
- :assets/alias-enabled? (or (storage/get :assets/alias-enabled?) false)
- :assets/alias-dirs (or (storage/get :assets/alias-dirs) [])
- ;; mobile
- :mobile/container-urls nil
- :mobile/show-action-bar? false
- :mobile/actioned-block nil
- :mobile/show-toolbar? false
- :mobile/show-recording-bar? false
- :mobile/show-tabbar? false
- ;;; Used to monitor mobile app status,
- ;;; value spec:
- ;;; {:is-active? bool, :timestamp int}
- :mobile/app-state-change (atom nil)
- ;; plugin
- :plugin/enabled (and util/plugin-platform?
- ;; true false :theme-only
- ((fnil identity true) (storage/get ::storage-spec/lsp-core-enabled)))
- :plugin/preferences nil
- :plugin/indicator-text nil
- :plugin/installed-plugins {}
- :plugin/installed-themes []
- :plugin/installed-slash-commands {}
- :plugin/installed-ui-items {}
- :plugin/installed-resources {}
- :plugin/installed-hooks {}
- :plugin/installed-services {}
- :plugin/simple-commands {}
- :plugin/selected-theme nil
- :plugin/selected-unpacked-pkg nil
- :plugin/marketplace-pkgs nil
- :plugin/marketplace-stats nil
- :plugin/installing nil
- :plugin/active-readme nil
- :plugin/updates-auto-checking? false
- :plugin/updates-pending {}
- :plugin/updates-coming {}
- :plugin/updates-downloading? false
- :plugin/updates-unchecked #{}
- :plugin/navs-settings? true
- :plugin/focused-settings nil ;; plugin id
- ;; pdf
- :pdf/system-win? false
- :pdf/current nil
- :pdf/ref-highlight nil
- :pdf/block-highlight-colored? (or (storage/get "ls-pdf-hl-block-is-colored") true)
- :pdf/auto-open-ctx-menu? (not= false (storage/get "ls-pdf-auto-open-ctx-menu"))
- ;; all notification contents as k-v pairs
- :notification/contents {}
- :graph/syncing? false
- ;; graph -> state
- :graph/parsing-state {}
- :copy/export-block-text-indent-style (or (storage/get :copy/export-block-text-indent-style)
- "dashes")
- :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
- #{})
- :copy/export-block-text-other-options (or (storage/get :copy/export-block-text-other-options)
- {})
- :date-picker/date nil
- :youtube/players {}
- ;; command palette
- :command-palette/commands (atom [])
- :view/components {}
- :view/selected-blocks nil
- :srs/mode? false
- :srs/cards-due-count nil
- :reactive/query-dbs {}
- ;; login, userinfo, token, ...
- :auth/refresh-token (storage/get "refresh-token")
- :auth/access-token nil
- :auth/id-token nil
- ;; file-sync
- :file-sync/jstour-inst nil
- :file-sync/onboarding-state (or (storage/get :file-sync/onboarding-state)
- {:welcome false})
- :file-sync/remote-graphs {:loading false :graphs nil}
- :file-sync/set-remote-graph-password-result {}
- ;; graph-uuid -> {:graphs-txid {}
- ;; :file-sync/sync-manager {}
- ;; :file-sync/sync-state {}
- ;; ;; {file-path -> payload}
- ;; :file-sync/progress {}
- ;; :file-sync/start-time {}
- ;; :file-sync/last-synced-at {}}
- :file-sync/graph-state {:current-graph-uuid nil}
- ;; graph-uuid -> ...
- :rtc/state (atom {})
- ;; only latest rtc-log stored here, when a log stream is needed,
- ;; use missionary to create a rtc-log-flow, use (missionary.core/watch <atom>)
- :rtc/log (atom nil)
- :rtc/uploading? false
- :rtc/downloading-graph-uuid nil
- :rtc/graphs []
- :rtc/online-info (atom {})
- :rtc/asset-upload-download-progress (atom {})
- :user/info {:UserGroups (storage/get :user-groups)}
- :encryption/graph-parsing? false
- :ui/loading? {}
- :ui/container-id (atom 0)
- :ui/cached-key->container-id (atom {})
- :feature/enable-sync? (storage/get :logseq-sync-enabled)
- :feature/enable-sync-diff-merge? ((fnil identity true) (storage/get :logseq-sync-diff-merge-enabled))
- :feature/enable-rtc? (storage/get :logseq-rtc-enabled)
- :file/rename-event-chan (async/chan 100)
- :ui/find-in-page nil
- :graph/importing nil
- :graph/importing-state {}
- :graph/loading? nil
- :handbook/route-chan (async/chan (async/sliding-buffer 1))
- :whiteboard/onboarding-whiteboard? (or (storage/get :ls-onboarding-whiteboard?) false)
- :whiteboard/onboarding-tour? (or (storage/get :whiteboard-onboarding-tour?) false)
- :whiteboard/last-persisted-at {}
- :whiteboard/pending-tx-data {}
- :system/info {}
- ;; Whether block is selected
- :ui/select-query-cache (atom {})
- :ui/toggle-highlight-recent-blocks? (atom false)
- :ui/highlight-recent-days (atom (or (storage/get :ui/highlight-recent-days)
- 3))
- :favorites/updated? (atom 0)
- :db/async-queries (atom {})
- :db/latest-transacted-entity-uuids (atom {})})))
- ;; User configuration getters under :config (and sometimes :me)
- ;; ========================================
- ;; TODO: Refactor default config values to be data driven. Currently they are all
- ;; buried in getters
- ;; TODO: Refactor our access to be more data driven. Currently each getter
- ;; (re-)fetches get-current-repo needlessly
- ;; TODO: Add consistent validation. Only a few config options validate at get time
- (def common-default-config
- "Common default config for a user's repo config"
- {:feature/enable-search-remove-accents? true
- :ui/auto-expand-block-refs? true
- ;; For flushing the settings of old versions. Don't bump this value.
- ;; There are only two kinds of graph, one is not upgraded (:legacy) and one is upgraded (:triple-lowbar)
- ;; For not upgraded graphs, the config will have no key `:file/name-format`
- ;; Then the default value is applied
- :file/name-format :legacy})
- (def file-default-config
- "Default repo config for file graphs"
- (merge common-default-config
- ;; The "NOW" query returns tasks with "NOW" or "DOING" status.
- ;; The "NEXT" query returns tasks with "NOW", "LATER", or "TODO" status.
- {:default-queries
- {:journals
- [{:title "🔨 NOW"
- :query '[:find (pull ?h [*])
- :in $ ?start ?today
- :where
- (task ?h #{"NOW" "DOING"})
- [?h :block/page ?p]
- [?p :block/journal-day ?d]
- [(>= ?d ?start)]
- [(<= ?d ?today)]]
- :inputs [:14d :today]
- :result-transform '(fn [result]
- (sort-by (fn [h]
- (get h :block/priority "Z")) result))
- :group-by-page? false
- :collapsed? false}
- {:title "📅 NEXT"
- :query '[:find (pull ?h [*])
- :in $ ?start ?next
- :where
- (task ?h #{"NOW" "LATER" "TODO"})
- [?h :block/page ?p]
- [?p :block/journal-day ?d]
- [(> ?d ?start)]
- [(< ?d ?next)]]
- :inputs [:today :7d-after]
- :group-by-page? false
- :collapsed? false}]}}))
- (def db-default-config
- "Default repo config for DB graphs"
- (merge common-default-config
- ;; The "DOING" query returns tasks with "Doing" status for recent past days
- ;; The "TODO" query returns tasks with "Todo" status for upcoming future days
- {:default-queries
- {:journals
- [{:title [:span (shui/tabler-icon "InProgress50" {:class "align-middle pr-1"}) [:span.align-middle "DOING"]]
- :query '[:find (pull ?b [*])
- :in $ ?start ?today
- :where
- (task ?b #{"Doing"})
- [?b :block/page ?p]
- [?p :block/journal-day ?d]
- [(>= ?d ?start)]
- [(<= ?d ?today)]]
- :inputs [:14d :today]
- :collapsed? false}
- {:title [:span (shui/tabler-icon "Todo" {:class "align-middle pr-1"}) [:span.align-middle "TODO"]]
- :query '[:find (pull ?b [*])
- :in $ ?start ?next
- :where
- (task ?b #{"Todo"})
- [?b :block/page ?p]
- [?p :block/journal-day ?d]
- [(> ?d ?start)]
- [(< ?d ?next)]]
- :inputs [:today :7d-after]
- :group-by-page? false
- :collapsed? false}]}
- :ui/hide-empty-properties? false}))
- ;; State that most user config is dependent on
- (declare get-current-repo sub set-state!)
- (defn merge-configs
- "Merges user configs in given orders. All values are overridden except for maps
- which are merged."
- [& configs]
- (->> configs
- (filter map?)
- (apply merge-with
- (fn merge-config [current new]
- (if (and (map? current) (map? new))
- (merge current new)
- new)))))
- (defn get-global-config
- []
- (get-in @state [:config ::global-config]))
- (defn get-global-config-str-content
- []
- (get-in @state [:config ::global-config-str-content]))
- (defn get-graph-config
- ([] (get-graph-config (get-current-repo)))
- ([repo-url] (get-in @state [:config repo-url])))
- (defn get-config
- "User config for the given repo or current repo if none given. All config fetching
- should be done through this fn in order to get global config and config defaults"
- ([]
- (get-config (get-current-repo)))
- ([repo-url]
- (merge-configs
- (if (sqlite-util/db-based-graph? repo-url) db-default-config file-default-config)
- (get-global-config)
- (get-graph-config repo-url))))
- (defn publishing-enable-editing?
- []
- (and common-config/PUBLISHING (:publishing/enable-editing? (get-config))))
- (defn enable-editing?
- []
- (or (not common-config/PUBLISHING) (:publishing/enable-editing? (get-config))))
- (defonce built-in-macros
- {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
- (defn get-macros
- []
- (merge
- built-in-macros
- (:macros (get-config))))
- (defn set-assets-alias-enabled!
- [v]
- (set-state! :assets/alias-enabled? (boolean v))
- (storage/set :assets/alias-enabled? (boolean v)))
- (defn set-assets-alias-dirs!
- [dirs]
- (when dirs
- (set-state! :assets/alias-dirs dirs)
- (storage/set :assets/alias-dirs dirs)))
- (defn get-custom-css-link
- []
- (:custom-css-url (get-config)))
- (defn get-custom-js-link
- []
- (:custom-js-url (get-config)))
- (defn get-default-journal-template
- []
- (when-let [template (get-in (get-config) [:default-templates :journals])]
- (when-not (string/blank? template)
- (string/trim template))))
- (defn all-pages-public?
- []
- (let [value (:publishing/all-pages-public? (get-config))
- value (if (some? value) value (:all-pages-public? (get-config)))]
- (true? value)))
- (defn get-default-home
- []
- (:default-home (get-config)))
- (defn custom-home-page?
- []
- (some? (:page (get-default-home))))
- (defn get-preferred-format
- ([]
- (get-preferred-format (get-current-repo)))
- ([repo-url]
- (keyword
- (or
- (common-config/get-preferred-format (get-config repo-url))
- (get-in @state [:me :preferred_format] "markdown")))))
- (defn markdown?
- []
- (= (keyword (get-preferred-format))
- :markdown))
- (defn get-pages-directory
- []
- (or
- (when-let [repo (get-current-repo)]
- (:pages-directory (get-config repo)))
- "pages"))
- (defn get-journals-directory
- []
- (or
- (when-let [repo (get-current-repo)]
- (:journals-directory (get-config repo)))
- "journals"))
- (defn get-whiteboards-directory
- []
- (or
- (when-let [repo (get-current-repo)]
- (:whiteboards-directory (get-config repo)))
- "whiteboards"))
- (defn org-mode-file-link?
- [repo]
- (:org-mode/insert-file-link? (get-config repo)))
- (defn get-journal-file-name-format
- []
- (when-let [repo (get-current-repo)]
- (:journal/file-name-format (get-config repo))))
- (defn get-preferred-workflow
- []
- (keyword
- (or
- (when-let [workflow (:preferred-workflow (get-config))]
- (let [workflow (name workflow)]
- (if (util/safe-re-find #"now|NOW" workflow)
- :now
- :todo)))
- (get-in @state [:me :preferred_workflow] :now))))
- (defn get-preferred-todo
- []
- (if (= (get-preferred-workflow) :now)
- "LATER"
- "TODO"))
- (defn get-filename-format
- ([] (get-filename-format (get-current-repo)))
- ([repo]
- (:file/name-format (get-config repo))))
- (defn get-date-formatter
- []
- (let [repo (get-current-repo)]
- (if (sqlite-util/db-based-graph? repo)
- (when-let [conn (db-conn-state/get-conn repo)]
- (get (entity-plus/entity-memoized @conn :logseq.class/Journal)
- :logseq.property.journal/title-format
- "MMM do, yyyy"))
- (common-config/get-date-formatter (get-config)))))
- (defn custom-shortcuts []
- (merge (storage/get :ls-shortcuts)
- (:shortcuts (get-config))))
- (defn get-commands
- []
- (:commands (get-config)))
- (defn get-scheduled-future-days
- []
- (let [days (:scheduled/future-days (get-config))]
- (or (when (int? days) days) 7)))
- (defn get-start-of-week
- []
- (or (:start-of-week (get-config))
- (get-in @state [:me :settings :start-of-week])
- 6))
- ;; TODO: support this later
- (comment
- (defn get-ref-open-blocks-level
- []
- (or
- (when-let [value (:ref/default-open-blocks-level (get-config))]
- (when (integer? value)
- value))
- 2)))
- (comment
- (defn get-linked-references-collapsed-threshold
- []
- (or
- (when-let [value (:ref/linked-references-collapsed-threshold (get-config))]
- (when (integer? value)
- value))
- 100)))
- (defn get-export-bullet-indentation
- []
- (case (get (get-config) :export/bullet-indentation :tab)
- :eight-spaces
- " "
- :four-spaces
- " "
- :two-spaces
- " "
- :tab
- "\t"))
- (defn enable-search-remove-accents?
- []
- (:feature/enable-search-remove-accents? (get-config)))
- ;; State cursor fns for use with rum components
- ;; ============================================
- (declare document-mode?)
- (defn sub
- "Creates a rum cursor, https://github.com/tonsky/rum#cursors, for use in rum components.
- Similar to re-frame subscriptions"
- [ks & {:keys [path-in-sub-atom]}]
- (let [ks-coll? (coll? ks)
- get-fn (if ks-coll? get-in get)
- s (get-fn @state ks)
- s-atom? (util/atom? s)
- path-coll?-in-sub-atom (coll? path-in-sub-atom)]
- (cond
- (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
- (util/react (rum/cursor-in s path-in-sub-atom))
- (and s-atom? path-in-sub-atom)
- (util/react (rum/cursor s path-in-sub-atom))
- s-atom? (util/react s)
- ks-coll? (util/react (rum/cursor-in state ks))
- :else (util/react (rum/cursor state ks)))))
- (defn set-editing-block-id!
- [container-block]
- (reset! (:editor/editing? @state) {container-block true}))
- (defn- sub-flow-state
- [flow watch-ref sub-value-f deps]
- (let [checkf (hooks/use-callback sub-value-f deps)
- init-value (checkf @watch-ref)
- flow (hooks/use-memo
- #(m/eduction
- (map checkf)
- (dedupe)
- (drop-while (fn [x] (identical? x init-value)))
- flow)
- [init-value])]
- (hooks/use-flow-state init-value flow)))
- (def ^:private editing-flow
- (m/watch (:editor/editing? @state)))
- (defn sub-editing?
- [container-block]
- (sub-flow-state editing-flow
- (:editor/editing? @state)
- (fn [s] (boolean (get s container-block)))
- [container-block]))
- (defn sub-config
- "Sub equivalent to get-config which should handle all sub user-config access"
- ([] (sub-config (get-current-repo)))
- ([repo]
- (let [config (sub :config)]
- (merge-configs (if (and (string? repo) (sqlite-util/db-based-graph? repo)) db-default-config file-default-config)
- (get config ::global-config)
- (get config repo)))))
- (defn enable-grammarly?
- []
- (true? (:feature/enable-grammarly? (sub-config))))
- (defn scheduled-deadlines-disabled?
- []
- (true? (:feature/disable-scheduled-and-deadline-query? (sub-config))))
- (defn enable-timetracking?
- []
- (not (false? (:feature/enable-timetracking? (sub-config)))))
- (defn enable-fold-button-right?
- []
- (let [_ (sub :ui/viewport)]
- (and (util/mobile?)
- (util/sm-breakpoint?))))
- (defn enable-journals?
- ([]
- (enable-journals? (get-current-repo)))
- ([repo]
- (not (false? (:feature/enable-journals? (sub-config repo))))))
- (defn enable-flashcards?
- ([]
- (enable-flashcards? (get-current-repo)))
- ([repo]
- (not (false? (:feature/enable-flashcards? (sub-config repo))))))
- (defn enable-sync?
- []
- (sub :feature/enable-sync?))
- (defn enable-sync-diff-merge?
- []
- (sub :feature/enable-sync-diff-merge?))
- (defn enable-whiteboards?
- ([]
- (enable-whiteboards? (get-current-repo)))
- ([repo]
- (not (false? (:feature/enable-whiteboards? (sub-config repo))))))
- (defn enable-rtc?
- []
- (sub :feature/enable-rtc?))
- (defn enable-git-auto-push?
- [repo]
- (not (false? (:git-auto-push (sub-config repo)))))
- (defn graph-settings
- []
- (:graph/settings (sub-config)))
- (defn graph-forcesettings
- []
- (:graph/forcesettings (sub-config)))
- ;; Enable by default
- (defn show-brackets?
- []
- (not (false? (:ui/show-brackets? (sub-config)))))
- (defn sub-default-home-page
- []
- (get-in (sub-config) [:default-home :page] ""))
- (defn- get-selected-block-ids
- [blocks]
- (->> blocks
- (remove nil?)
- (keep #(when-let [id (dom/attr % "blockid")]
- (uuid id)))
- (distinct)))
- (defn block-content-max-length
- [repo]
- (or (:block/title-max-length (sub-config repo))
- ;; backward compatible
- (:block/content-max-length (sub-config repo))
- 10000))
- (defn mobile?
- []
- (or (util/mobile?) (mobile-util/native-platform?)))
- (defn enable-tooltip?
- []
- (if (mobile?)
- false
- (get (sub-config) :ui/enable-tooltip? true)))
- (defn show-command-doc?
- []
- (get (sub-config) :ui/show-command-doc? true))
- (defn logical-outdenting?
- []
- (:editor/logical-outdenting? (sub-config)))
- (defn show-full-blocks?
- []
- (:ui/show-full-blocks? (sub-config)))
- (defn preferred-pasting-file?
- []
- (:editor/preferred-pasting-file? (sub-config)))
- (defn auto-expand-block-refs?
- []
- (:ui/auto-expand-block-refs? (sub-config)))
- (defn doc-mode-enter-for-new-line?
- []
- (and (document-mode?)
- (not (:shortcut/doc-mode-enter-for-new-block? (get-config)))))
- (defn user-groups
- []
- (set (sub [:user/info :UserGroups])))
- ;; State mutation helpers
- ;; ======================
- (defn set-state!
- [path value & {:keys [path-in-sub-atom]}]
- (vswap! *profile-state update path inc)
- (let [path-coll? (coll? path)
- get-fn (if path-coll? get-in get)
- s (get-fn @state path)
- s-atom? (util/atom? s)
- path-coll?-in-sub-atom (coll? path-in-sub-atom)]
- (cond
- (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
- (let [old-v (get-in @s path-in-sub-atom)]
- (when (not= old-v value)
- (swap! s assoc-in path-in-sub-atom value)))
- (and s-atom? path-in-sub-atom)
- (let [old-v (get @s path-in-sub-atom)]
- (when (not= old-v value)
- (swap! s assoc path-in-sub-atom value)))
- s-atom?
- (when (not= @s value)
- (reset! s value))
- path-coll?
- (when (not= s value)
- (swap! state assoc-in path value))
- :else
- (when (not= s value)
- (swap! state assoc path value))))
- nil)
- (defn update-state!
- [path f & {:keys [path-in-sub-atom]}]
- (vswap! *profile-state update path inc)
- (let [path-coll? (coll? path)
- get-fn (if path-coll? get-in get)
- s (get-fn @state path)
- s-atom? (util/atom? s)
- path-coll?-in-sub-atom (coll? path-in-sub-atom)]
- (cond
- (and s-atom? path-in-sub-atom path-coll?-in-sub-atom)
- (swap! s update-in path-in-sub-atom f)
- (and s-atom? path-in-sub-atom)
- (swap! s update path-in-sub-atom f)
- s-atom? (swap! s f)
- path-coll? (swap! state update-in path f)
- :else (swap! state update path f)))
- nil)
- ;; State getters and setters
- ;; =========================
- ;; These fns handle any key except :config.
- ;; Some state is also stored in local storage and/or sent to electron's main process
- (defn get-route-match
- []
- (:route-match @state))
- (defn get-current-route
- []
- (get-in (get-route-match) [:data :name]))
- (defn home?
- []
- (= :home (get-current-route)))
- (defn whiteboard-dashboard?
- []
- (= :whiteboards (get-current-route)))
- (defn get-current-page
- []
- (when (= :page (get-current-route))
- (get-in (get-route-match)
- [:path-params :name])))
- (defn route-has-p?
- []
- (get-in (get-route-match) [:query-params :p]))
- (defn get-current-repo
- "Returns the current repo URL, or else open demo graph"
- []
- (:git/current-repo @state))
- (defn get-remote-file-graphs
- []
- (get-in @state [:file-sync/remote-graphs :graphs]))
- (defn get-rtc-graphs
- []
- (:rtc/graphs @state))
- (defn get-remote-graph-info-by-uuid
- [uuid]
- (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
- (some #(when (= (:GraphUUID %) (str uuid)) %) graphs)))
- (defn get-remote-graph-usage
- []
- (when-let [graphs (seq (get-in @state [:file-sync/remote-graphs :graphs]))]
- (->> graphs
- (map #(hash-map :uuid (:GraphUUID %)
- :name (:GraphName %)
- :used-gbs (/ (:GraphStorageUsage %) 1024 1024 1024)
- :limit-gbs (/ (:GraphStorageLimit %) 1024 1024 1024)
- :used-percent (/ (:GraphStorageUsage %) (:GraphStorageLimit %) 0.01)))
- (map #(assoc % :free-gbs (- (:limit-gbs %) (:used-gbs %))))
- (vec))))
- (defn delete-remote-graph!
- [repo]
- (let [remove-repo! (fn [repos]
- (remove #(and
- (:GraphUUID repo)
- (:GraphUUID %)
- (= (:GraphUUID repo) (:GraphUUID %))) repos))]
- (if (:rtc-graph? repo)
- (swap! state update :rtc/graphs remove-repo!)
- (swap! state update-in [:file-sync/remote-graphs :graphs] remove-repo!))))
- (defn add-remote-graph!
- [repo]
- (swap! state update-in [:file-sync/remote-graphs :graphs]
- (fn [repos]
- (->> (conj repos repo)
- (distinct)))))
- (defn get-repos
- []
- (get-in @state [:me :repos]))
- (defn set-repos!
- [repos]
- (set-state! [:me :repos] (distinct repos)))
- (defn add-repo!
- [repo]
- (when (not (string/blank? repo))
- (update-state! [:me :repos]
- (fn [repos]
- (->> (conj repos repo)
- (distinct))))))
- (defn set-current-repo!
- [repo]
- (swap! state assoc :git/current-repo repo)
- (reset! flows/*current-repo repo)
- (if repo
- (storage/set :git/current-repo repo)
- (storage/remove :git/current-repo))
- (ipc/ipc "setCurrentGraph" repo))
- (defn set-preferred-format!
- [format]
- (swap! state assoc-in [:me :preferred_format] (name format)))
- (defn set-preferred-workflow!
- [workflow]
- (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
- (defn set-preferred-language!
- [language]
- (set-state! :preferred-language (name language))
- (storage/set :preferred-language (name language)))
- (defn delete-repo!
- [repo]
- (swap! state update-in [:me :repos]
- (fn [repos]
- (->> (remove #(or (= (:url repo) (:url %))
- (and
- (:GraphUUID repo)
- (:GraphUUID %)
- (= (:GraphUUID repo) (:GraphUUID %)))) repos)
- (util/distinct-by :url)))))
- (defn set-timestamp-block!
- [value]
- (set-state! :editor/set-timestamp-block value))
- (defn get-timestamp-block
- []
- @(:editor/set-timestamp-block @state))
- (defn get-edit-block
- []
- @(get @state :editor/block))
- (defn editing?
- []
- (seq @(:editor/editing? @state)))
- (defn get-edit-input-id
- []
- (when-not (exists? js/process)
- (when (editing?)
- (try
- (when-let [elem (or (when-let [id (:block/uuid (get-edit-block))]
- (gdom/getElement (str "edit-block-" id)))
- js/document.activeElement)]
- (when (util/input? elem)
- (let [id (gobj/get elem "id")]
- (when (string/starts-with? id "edit-block-")
- id))))
- (catch :default _e)))))
- (defn set-edit-content!
- ([value] (set-edit-content! (get-edit-input-id) value))
- ([input-id value] (set-edit-content! input-id value true))
- ([input-id value set-input-value?]
- (when input-id
- (when set-input-value?
- (when-let [input (gdom/getElement input-id)]
- (util/set-change-value input value)))
- (set-state! :editor/content value :path-in-sub-atom
- (or (:block/uuid (get-edit-block)) input-id)))))
- (defn get-input
- []
- (when-let [id (get-edit-input-id)]
- (gdom/getElement id)))
- (defn get-edit-content
- []
- (when-let [id (:block/uuid (get-edit-block))]
- (get @(:editor/content @state) id)))
- (defn sub-edit-content
- ([]
- (sub-edit-content (:block/uuid (get-edit-block))))
- ([block-id]
- (when block-id
- (sub :editor/content {:path-in-sub-atom block-id}))))
- (defn set-selection-start-block!
- [start-block]
- (set-state! :selection/start-block start-block))
- (defn get-selection-start-block
- []
- (or @(get @state :selection/start-block)
- (when-let [edit-block (get-edit-block)]
- (let [id (str "ls-block-" (:block/uuid edit-block))]
- (set-selection-start-block! id)
- id))))
- (defn get-cursor-range
- []
- @(:editor/cursor-range @state))
- (defn set-cursor-range!
- [range]
- (set-state! :editor/cursor-range range))
- (defn set-search-mode!
- ([value] (set-search-mode! value nil))
- ([value args]
- (set-state! :search/mode value)
- (set-state! :search/args args)))
- (defn set-editor-action!
- [value]
- (set-state! :editor/action value))
- (defn set-editor-action-data!
- [value]
- (set-state! :editor/action-data value))
- (defn get-editor-action
- []
- @(:editor/action @state))
- (defn get-editor-action-data
- []
- (:editor/action-data @state))
- (defn get-editor-show-page-search?
- []
- (= (get-editor-action) :page-search))
- (defn get-editor-show-page-search-hashtag?
- []
- (= (get-editor-action) :page-search-hashtag))
- (defn get-editor-show-block-search?
- []
- (= (get-editor-action) :block-search))
- (defn set-editor-show-input!
- [value]
- (if value
- (do
- (set-editor-action-data! (assoc (get-editor-action-data) :options value))
- (set-editor-action! :input))
- (do
- (set-editor-action! nil)
- (set-editor-action-data! nil))))
- (defn get-editor-show-input
- []
- (when (= (get-editor-action) :input)
- (get @state :editor/action-data)))
- (defn set-editor-show-commands!
- []
- (when-not (get-editor-action) (set-editor-action! :commands)))
- (defn clear-editor-action!
- []
- (set-state! :editor/action nil))
- (defn get-edit-pos
- []
- (when-let [input (get-input)]
- (util/get-selection-start input)))
- (defn get-selection-direction
- []
- @(:selection/direction @state))
- (defn get-unsorted-selection-blocks
- []
- @(:selection/blocks @state))
- (defn get-selection-blocks
- []
- (let [result (get-unsorted-selection-blocks)
- direction (get-selection-direction)]
- (if (= direction :up)
- (vec (reverse result))
- result)))
- (defn get-selection-block-ids
- []
- (get-selected-block-ids (get-selection-blocks)))
- (def ^:private block-selected-flow
- (m/watch (:selection/blocks @state)))
- (defn sub-block-selected?
- [block-id]
- (assert (uuid? block-id))
- (sub-flow-state block-selected-flow
- (:selection/blocks @state)
- (fn [blocks]
- (some #{block-id} (get-selected-block-ids blocks)))
- [block-id]))
- (defn dom-clear-selection!
- []
- (doseq [node (dom/by-class "ls-block selected")]
- (dom/remove-class! node "selected")))
- (defn mark-dom-blocks-as-selected
- [nodes]
- (doseq [node nodes]
- (dom/add-class! node "selected")))
- (defn get-events-chan
- []
- (:system/events @state))
- (defn pub-event!
- {:malli/schema [:=> [:cat vector?] :any]}
- [payload]
- (let [d (p/deferred)
- chan (get-events-chan)]
- (async/put! chan [payload d])
- d))
- (defn- set-selection-blocks-aux!
- [blocks]
- (set-state! :view/selected-blocks nil)
- (let [selected-ids (set (get-selected-block-ids @(:selection/blocks @state)))
- _ (set-state! :selection/blocks blocks)
- new-ids (set (get-selection-block-ids))
- removed (set/difference selected-ids new-ids)]
- (mark-dom-blocks-as-selected blocks)
- (doseq [id removed]
- (doseq [node (array-seq (gdom/getElementsByClass (str "id" id)))]
- (dom/remove-class! node "selected")))))
- (defn set-selection-blocks!
- ([blocks]
- (set-selection-blocks! blocks nil))
- ([blocks direction]
- (when (seq blocks)
- (let [blocks (vec (remove nil? blocks))]
- (set-selection-blocks-aux! blocks)
- (when direction (set-state! :selection/direction direction))
- (let [ids (get-selection-block-ids)]
- (when (seq ids) (pub-event! [:editor/load-blocks ids])))))))
- (defn state-clear-selection!
- []
- (set-state! :selection/blocks nil)
- (set-state! :selection/direction nil)
- (set-state! :selection/start-block nil)
- (set-state! :selection/selected-all? false)
- (pub-event! [:editor/hide-action-bar]))
- (defn clear-selection!
- []
- (dom-clear-selection!)
- (state-clear-selection!))
- (defn get-selection-start-block-or-first
- []
- (or (get-selection-start-block)
- (some-> (first (get-selection-blocks))
- (gobj/get "id"))))
- (defn selection?
- "True sense of selection mode with valid selected block"
- []
- (seq (get-selection-blocks)))
- (defn conj-selection-block!
- [block-or-blocks direction]
- (let [selection-blocks (get-unsorted-selection-blocks)
- block-or-blocks (if (sequential? block-or-blocks) block-or-blocks [block-or-blocks])
- blocks (-> (concat selection-blocks block-or-blocks)
- distinct)]
- (set-selection-blocks! blocks direction)))
- (defn drop-selection-block!
- [block]
- (set-selection-blocks-aux! (-> (remove #(= block %) (get-unsorted-selection-blocks))
- vec)))
- (defn drop-selection-blocks-starts-with!
- [block]
- (let [blocks (get-unsorted-selection-blocks)
- blocks' (-> (take-while (fn [b] (not= (.-id b) (.-id block))) blocks)
- vec
- (conj block))]
- (set-selection-blocks-aux! blocks')))
- (defn drop-last-selection-block!
- []
- (let [blocks @(:selection/blocks @state)
- blocks' (vec (butlast blocks))]
- (set-selection-blocks-aux! blocks')
- (last blocks)))
- (defn hide-custom-context-menu!
- []
- (swap! state assoc
- :custom-context-menu/show? false
- :custom-context-menu/links nil
- :custom-context-menu/position nil))
- (defn toggle-navigation-item-collapsed!
- [item]
- (update-state! [:ui/navigation-item-collapsed? item] not))
- (defn toggle-sidebar-open?!
- []
- (swap! state update :ui/sidebar-open? not))
- (defn open-right-sidebar!
- []
- (swap! state assoc :ui/sidebar-open? true))
- (defn hide-right-sidebar!
- []
- (swap! state assoc :ui/sidebar-open? false))
- (defn sidebar-move-block!
- [from to]
- (update-state! :sidebar/blocks (fn [blocks]
- (let [to (if (> from to) (inc to) to)]
- (if (not= to from)
- (let [item (nth blocks from)
- blocks (keep-indexed #(when (not= %1 from) %2) blocks)
- [l r] (split-at to blocks)]
- (concat l [item] r))
- blocks)))))
- (defn sidebar-remove-block!
- [idx]
- (update-state! :sidebar/blocks (fn [blocks]
- (if (string? idx)
- (remove #(= (second %) idx) blocks)
- (util/drop-nth idx blocks))))
- (when (empty? (:sidebar/blocks @state))
- (hide-right-sidebar!)))
- (defn sidebar-remove-deleted-block!
- [ids]
- (let [ids-set (set ids)]
- (update-state! :sidebar/blocks (fn [items]
- (remove (fn [[repo id _]]
- (and (= repo (get-current-repo)) (contains? ids-set id))) items)))
- (when (empty? (:sidebar/blocks @state))
- (hide-right-sidebar!))))
- (defn sidebar-remove-rest!
- [db-id]
- (update-state! :sidebar/blocks (fn [blocks]
- (remove #(not= (second %) db-id) blocks)))
- (set-state! [:ui/sidebar-collapsed-blocks db-id] false))
- (defn sidebar-replace-block!
- [old-sidebar-key new-sidebar-key]
- (update-state! :sidebar/blocks (fn [blocks]
- (map #(if (= % old-sidebar-key)
- new-sidebar-key
- %) blocks))))
- (defn sidebar-block-exists?
- [idx]
- (some #(= (second %) idx) (:sidebar/blocks @state)))
- (defn clear-sidebar-blocks!
- []
- (set-state! :sidebar/blocks '()))
- (defn sidebar-block-toggle-collapse!
- [db-id]
- (when db-id
- (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
- (defn sidebar-block-collapse-rest!
- [db-id]
- (let [items (disj (set (map second (:sidebar/blocks @state))) db-id)]
- (doseq [item items] (set-state! [:ui/sidebar-collapsed-blocks item] true))))
- (defn sidebar-block-set-collapsed-all!
- [collapsed?]
- (let [items (map second (:sidebar/blocks @state))]
- (doseq [item items]
- (set-state! [:ui/sidebar-collapsed-blocks item] collapsed?))))
- (defn clear-editor-last-pos!
- []
- (set-state! :editor/last-saved-cursor {}))
- (defn clear-cursor-range!
- []
- (set-state! :editor/cursor-range nil))
- (defn clear-edit!
- [& {:keys [clear-editing-block?]
- :or {clear-editing-block? true}}]
- (clear-editor-action!)
- (when clear-editing-block?
- (set-state! :editor/editing? {})
- (set-state! :editor/block nil))
- (set-state! :editor/start-pos nil)
- (clear-editor-last-pos!)
- (clear-cursor-range!)
- (set-state! :editor/content {})
- (set-state! :ui/select-query-cache {})
- (set-state! :editor/block-refs #{})
- (set-state! :editor/action-data nil)
- (set-state! :view/selected-blocks nil))
- (defn into-code-editor-mode!
- []
- (set-state! :editor/cursor-range nil)
- (swap! state assoc :editor/code-mode? true))
- (defn set-editor-last-pos!
- [new-pos]
- (update-state! :editor/last-saved-cursor
- (fn [m] (assoc m (:block/uuid (get-edit-block)) new-pos))))
- (defn get-editor-last-pos
- []
- (get @(:editor/last-saved-cursor @state) (:block/uuid (get-edit-block))))
- (defn set-block-content-and-last-pos!
- [edit-input-id content new-pos]
- (when edit-input-id
- (set-edit-content! edit-input-id content)
- (set-editor-last-pos! new-pos)))
- (defn set-theme-mode!
- [mode]
- (when (mobile-util/native-platform?)
- (if (= mode "light")
- (util/set-theme-light)
- (util/set-theme-dark)))
- (set-state! :ui/theme mode)
- (storage/set :ui/theme mode))
- (defn sync-system-theme!
- []
- (let [system-dark? (.-matches (js/window.matchMedia "(prefers-color-scheme: dark)"))]
- (set-theme-mode! (if system-dark? "dark" "light"))
- (set-state! :ui/system-theme? true)
- (storage/set :ui/system-theme? true)))
- (defn use-theme-mode!
- [theme-mode]
- (if (= theme-mode "system")
- (sync-system-theme!)
- (do
- (set-theme-mode! theme-mode)
- (set-state! :ui/system-theme? false)
- (storage/set :ui/system-theme? false))))
- (defn- toggle-theme
- [theme]
- (if (= theme "dark") "light" "dark"))
- (defn toggle-theme!
- []
- (use-theme-mode! (toggle-theme (:ui/theme @state))))
- (defn set-custom-theme!
- ([custom-theme]
- (set-custom-theme! nil custom-theme))
- ([mode theme]
- (set-state! (if mode [:ui/custom-theme (keyword mode)] :ui/custom-theme) theme)
- (storage/set :ui/custom-theme (:ui/custom-theme @state))))
- (defn restore-mobile-theme!
- "Restore mobile theme setting from local storage"
- []
- (let [mode (or (storage/get :ui/theme) "light")
- system-theme? (storage/get :ui/system-theme?)]
- (when (and (not system-theme?)
- (mobile-util/native-platform?))
- (if (= mode "light")
- (util/set-theme-light)
- (util/set-theme-dark)))))
- (defn set-editing-block-dom-id!
- [block-dom-id]
- (set-state! :editor/block-dom-id block-dom-id))
- (defn get-editing-block-dom-id
- []
- @(:editor/block-dom-id @state))
- (defn set-root-component!
- [component]
- (set-state! :ui/root-component component))
- (defn get-root-component
- []
- (get @state :ui/root-component))
- (defn load-app-user-cfgs
- ([] (load-app-user-cfgs false))
- ([refresh?]
- (when (util/electron?)
- (p/let [cfgs (if (or refresh? (nil? (:electron/user-cfgs @state)))
- (ipc/ipc :userAppCfgs)
- (:electron/user-cfgs @state))
- cfgs (if (object? cfgs) (bean/->clj cfgs) cfgs)]
- (set-state! :electron/user-cfgs cfgs)))))
- (defn setup-electron-updater!
- []
- (when (util/electron?)
- (js/window.apis.setUpdatesCallback
- (fn [_ args]
- (let [data (bean/->clj args)
- pending? (not= (:type data) "completed")]
- (set-state! :electron/updater-pending? pending?)
- (when pending? (set-state! :electron/updater data))
- nil)))))
- (defn set-file-component!
- [component]
- (set-state! :ui/file-component component))
- (defn clear-file-component!
- []
- (set-state! :ui/file-component nil))
- (defn save-scroll-position!
- ([value]
- (save-scroll-position! value js/window.location.hash))
- ([value path]
- (set-state! :ui/paths-scroll-positions value :path-in-sub-atom path)))
- (defn save-main-container-position!
- [value]
- (when (not= value @(:ui/main-container-scroll-top @state))
- (set-state! :ui/main-container-scroll-top value)))
- (defn get-saved-scroll-position
- ([]
- (get-saved-scroll-position js/window.location.hash))
- ([path]
- (get @(get @state :ui/paths-scroll-positions) path 0)))
- (defn set-today!
- [value]
- (set-state! :today value))
- (defn get-me
- []
- (:me @state))
- (defn set-db-restoring!
- [value]
- (set-state! :db/restoring? value))
- (defn set-indexedb-support!
- [value]
- (set-state! :indexeddb/support? value))
- (defn modal-opened?
- []
- (shui-dialog/has-modal?))
- (defn close-modal! []
- (shui/dialog-close!))
- (defn get-reactive-custom-queries-chan
- []
- (:reactive/custom-queries @state))
- (defn get-left-sidebar-open?
- []
- (get-in @state [:ui/left-sidebar-open?]))
- (defn set-left-sidebar-open!
- [value]
- (storage/set "ls-left-sidebar-open?" (boolean value))
- (set-state! :ui/left-sidebar-open? value))
- (defn toggle-left-sidebar!
- []
- (set-left-sidebar-open!
- (not (get-left-sidebar-open?))))
- (defn set-developer-mode!
- [value]
- (set-state! :ui/developer-mode? value)
- (storage/set "developer-mode" (str value)))
- (defn developer-mode?
- []
- (:ui/developer-mode? @state))
- (defn get-notification-contents
- []
- (get @state :notification/contents))
- (defn document-mode?
- []
- (get @state :document/mode?))
- (defn toggle-document-mode!
- []
- (let [mode (document-mode?)]
- (set-state! :document/mode? (not mode))
- (storage/set :document/mode? (not mode))))
- (defn toggle-highlight-recent-blocks!
- []
- (let [value @(:ui/toggle-highlight-recent-blocks? @state)]
- (set-state! :ui/toggle-highlight-recent-blocks? (not value))))
- (defn shortcut-tooltip-enabled?
- []
- (get @state :ui/shortcut-tooltip?))
- (defn toggle-shortcut-tooltip!
- []
- (let [mode (shortcut-tooltip-enabled?)]
- (set-state! :ui/shortcut-tooltip? (not mode))
- (storage/set :ui/shortcut-tooltip? (not mode))))
- (defn set-config!
- [repo-url value]
- (when value (set-state! [:config repo-url] value)))
- (defn set-global-config!
- [value str-content]
- ;; Placed under :config so cursors can work seamlessly
- (when value
- (set-config! ::global-config value)
- (set-config! ::global-config-str-content str-content)))
- (defn get-wide-mode?
- []
- (:ui/wide-mode? @state))
- (defn toggle-wide-mode!
- []
- (update-state! :ui/wide-mode? not))
- (defn set-online!
- [value]
- (set-state! :network/online? value)
- ;; to avoid watch whole big state atom,
- ;; there's an atom flows/*network-online?,
- ;; then we can use flows/network-online-event-flow
- (reset! flows/*network-online? value))
- (defn get-plugins-slash-commands
- []
- (mapcat seq (flatten (vals (:plugin/installed-slash-commands @state)))))
- (defn get-plugins-commands-with-type
- [type]
- (->> (apply concat (vals (:plugin/simple-commands @state)))
- (filterv #(= (keyword (first %)) (keyword type)))))
- (defn get-plugins-ui-items-with-type
- [type]
- (->> (apply concat (vals (:plugin/installed-ui-items @state)))
- (filterv #(= (keyword (first %)) (keyword type)))))
- (defn get-plugin-resources-with-type
- [pid type]
- (when-let [pid (and type (keyword pid))]
- (get-in @state [:plugin/installed-resources pid (keyword type)])))
- (defn get-plugin-resource
- [pid type key]
- (when-let [resources (get-plugin-resources-with-type pid type)]
- (get resources key)))
- (defn upt-plugin-resource
- [pid type key attr val]
- (when-let [resource (get-plugin-resource pid type key)]
- (let [resource (assoc resource (keyword attr) val)]
- (set-state!
- [:plugin/installed-resources (keyword pid) (keyword type) key] resource)
- resource)))
- (defn get-plugin-services
- [pid type]
- (when-let [installed (and pid (:plugin/installed-services @state))]
- (some->> (seq (get installed (keyword pid)))
- (filterv #(= type (:type %))))))
- (defn install-plugin-service
- ([pid type name] (install-plugin-service pid type name nil))
- ([pid type name opts]
- (when-let [pid (and pid type name (keyword pid))]
- (let [exists (get-plugin-services pid type)]
- (when-let [service (and (or (not exists) (not (some #(= name (:name %)) exists)))
- {:pid pid :type type :name name :opts opts})]
- (update-state! [:plugin/installed-services pid] #(conj (vec %) service))
- ;; search engines state for results
- (when (= type :search)
- (set-state! [:search/engines (str pid name)] service)))))))
- (defn uninstall-plugin-service
- [pid type-or-all]
- (when-let [pid (keyword pid)]
- (when-let [installed (get (:plugin/installed-services @state) pid)]
- (let [remove-all? (or (true? type-or-all) (nil? type-or-all))
- remains (if remove-all? nil (filterv #(not= type-or-all (:type %)) installed))
- removed (if remove-all? installed (filterv #(= type-or-all (:type %)) installed))]
- (set-state! [:plugin/installed-services pid] remains)
- ;; search engines state for results
- (when-let [removed' (seq (filter #(= :search (:type %)) removed))]
- (update-state! :search/engines #(apply dissoc % (mapv (fn [{:keys [pid name]}] (str pid name)) removed'))))))))
- (defn get-all-plugin-services-with-type
- [type]
- (when-let [installed (vals (:plugin/installed-services @state))]
- (mapcat (fn [s] (filter #(= (keyword type) (:type %)) s)) installed)))
- (defn get-all-plugin-search-engines
- []
- (:search/engines @state))
- (defn update-plugin-search-engine
- [pid name f]
- (when-let [pid (keyword pid)]
- (set-state! :search/engines
- (update-vals (get-all-plugin-search-engines)
- #(if (and (= pid (:pid %)) (= name (:name %)))
- (f %) %)))))
- (defn reset-plugin-search-engines
- []
- (when-let [engines (get-all-plugin-search-engines)]
- (set-state! :search/engines
- (update-vals engines #(assoc % :result nil)))))
- (defn install-plugin-hook
- ([pid hook] (install-plugin-hook pid hook true))
- ([pid hook opts]
- (when-let [pid (keyword pid)]
- (set-state!
- [:plugin/installed-hooks hook]
- (assoc
- ((fnil identity {}) (get-in @state [:plugin/installed-hooks hook]))
- pid opts)) true)))
- (defn uninstall-plugin-hook
- [pid hook-or-all]
- (when-let [pid (keyword pid)]
- (if (nil? hook-or-all)
- (swap! state update :plugin/installed-hooks #(update-vals % (fn [ids] (dissoc ids pid))))
- (when-let [coll (get-in @state [:plugin/installed-hooks hook-or-all])]
- (set-state! [:plugin/installed-hooks hook-or-all] (dissoc coll pid))))
- true))
- (defn slot-hook-exist?
- [uuid]
- (when-let [type (and uuid (string/replace (str uuid) "-" "_"))]
- (when-let [hooks (sub :plugin/installed-hooks)]
- (contains? hooks (str "hook:editor:slot_" type)))))
- (defn active-tldraw-app
- []
- (when-let [tldraw-el (.querySelector js/document.body ".logseq-tldraw[data-tlapp]")]
- (gobj/get js/window.tlapps (.. tldraw-el -dataset -tlapp))))
- (defn tldraw-editing-logseq-block?
- []
- (when-let [app (active-tldraw-app)]
- (and (= 1 (.. app -selectedShapesArray -length))
- (= (.. app -editingShape) (.. app -selectedShapesArray (at 0))))))
- (defn set-graph-syncing?
- [value]
- (set-state! :graph/syncing? value))
- (defn set-editor-in-composition!
- [value]
- (set-state! :editor/in-composition? value))
- (defn editor-in-composition?
- []
- (:editor/in-composition? @state))
- (defn set-loading-files!
- [repo value]
- (when repo
- (set-state! [:repo/loading-files? repo] value)))
- (defn loading-files?
- [repo]
- (get-in @state [:repo/loading-files? repo]))
- (defn set-editor-last-input-time!
- [repo time]
- (set-state! :editor/last-input-time time :path-in-sub-atom repo))
- (defn input-idle?
- [repo & {:keys [diff]
- :or {diff 1000}}]
- (when repo
- (let [last-input-time (get @(get @state :editor/last-input-time) repo)]
- (or
- (nil? last-input-time)
- (let [now (util/time-ms)]
- (>= (- now last-input-time) diff))
- ;; not in editing mode
- ;; Is this a good idea to put whiteboard check here?
- (not (get-edit-input-id))))))
- (defn set-nfs-refreshing!
- [value]
- (set-state! :nfs/refreshing? value))
- (defn nfs-refreshing?
- []
- (:nfs/refreshing? @state))
- (defn set-search-result!
- [value]
- (set-state! :search/result value))
- (defn clear-search-result!
- []
- (set-search-result! nil))
- (defn add-graph-search-filter!
- [q]
- (when-not (string/blank? q)
- (update-state! :search/graph-filters
- (fn [value]
- (vec (distinct (conj value q)))))))
- (defn remove-search-filter!
- [q]
- (when-not (string/blank? q)
- (update-state! :search/graph-filters
- (fn [value]
- (remove #{q} value)))))
- (defn clear-search-filters!
- []
- (set-state! :search/graph-filters []))
- (defn get-search-mode
- []
- (:search/mode @state))
- (defn toggle!
- [path]
- (update-state! path not))
- (defn toggle-settings!
- []
- (toggle! :ui/settings-open?))
- (defn settings-open?
- []
- (:ui/settings-open? @state))
- (defn close-settings!
- []
- (set-state! :ui/settings-open? false))
- (defn open-settings!
- ([] (open-settings! true))
- ([active-tab] (set-state! :ui/settings-open? active-tab)))
- (defn sidebar-add-block!
- [repo db-id block-type]
- (when (not (util/sm-breakpoint?))
- (let [page (and (sqlite-util/db-based-graph? repo)
- (= :page block-type)
- (some-> (db-conn-state/get-conn repo) deref (d/entity db-id)))]
- (if (and page
- ;; TODO: Use config/dev? when it's not a circular dep
- (not goog.DEBUG)
- (or (ldb/hidden? page)
- (and (ldb/built-in? page) (ldb/private-built-in-page? page))))
- (pub-event! [:notification/show {:content "Cannot open an internal page." :status :warning}])
- (when db-id
- (update-state! :sidebar/blocks (fn [blocks]
- (->> (remove #(= (second %) db-id) blocks)
- (cons [repo db-id block-type])
- (distinct))))
- (set-state! [:ui/sidebar-collapsed-blocks db-id] false)
- (open-right-sidebar!)
- (when-let [elem (gdom/getElementByClass "sidebar-item-list")]
- (util/scroll-to elem 0)))))))
- (defn get-export-block-text-indent-style []
- (:copy/export-block-text-indent-style @state))
- (defn set-export-block-text-indent-style!
- [v]
- (set-state! :copy/export-block-text-indent-style v)
- (storage/set :copy/export-block-text-indent-style v))
- (defn get-recent-pages
- []
- (get-in @state [:ui/recent-pages (get-current-repo)]))
- (defn set-recent-pages!
- [v]
- (set-state! [:ui/recent-pages (get-current-repo)] v)
- (storage/set :ui/recent-pages (:ui/recent-pages @state)))
- (defn get-export-block-text-remove-options []
- (:copy/export-block-text-remove-options @state))
- (defn update-export-block-text-remove-options!
- [e k]
- (let [f (if (util/echecked? e) conj disj)]
- (update-state! :copy/export-block-text-remove-options
- #(f % k))
- (storage/set :copy/export-block-text-remove-options
- (get-export-block-text-remove-options))))
- (defn get-export-block-text-other-options []
- (:copy/export-block-text-other-options @state))
- (defn update-export-block-text-other-options!
- [k v]
- (update-state! :copy/export-block-text-other-options #(assoc % k v)))
- (defn set-editor-args!
- [args]
- (set-state! :editor/args args))
- (defn editing-whiteboard-portal?
- []
- (and (active-tldraw-app) (tldraw-editing-logseq-block?)))
- (defn block-component-editing?
- []
- (and (:block/component-editing-mode? @state)
- (not (editing-whiteboard-portal?))))
- (defn set-block-component-editing-mode!
- [value]
- (set-state! :block/component-editing-mode? value))
- (defn get-editor-args
- []
- @(:editor/args @state))
- (defn set-page-blocks-cp!
- [value]
- (set-state! [:view/components :page-blocks] value))
- (defn get-page-blocks-cp
- []
- (get-in @state [:view/components :page-blocks]))
- ;; To avoid circular dependencies
- (defn set-component!
- [k value]
- (set-state! [:view/components k] value))
- (defn get-component
- [k]
- (get-in @state [:view/components k]))
- (defn exit-editing-and-set-selected-blocks!
- ([blocks]
- (exit-editing-and-set-selected-blocks! blocks nil))
- ([blocks direction]
- (clear-edit!)
- (set-selection-blocks! blocks direction)))
- (defn set-editing!
- [edit-input-id content block cursor-range & {:keys [db move-cursor? container-id property-block direction event pos]
- :or {move-cursor? true}}]
- (when-not (exists? js/process)
- (when (and edit-input-id block
- (or
- (publishing-enable-editing?)
- (not common-config/PUBLISHING)))
- (let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
- container (util/get-block-container block-element)
- block (if container
- (assoc block
- :block.temp/container (gobj/get container "id"))
- block)
- block (assoc block :block.editing/direction direction
- :block.editing/event event
- :block.editing/pos pos)
- content (string/trim (or content ""))]
- (assert (and container-id (:block/uuid block))
- "container-id or block uuid is missing")
- (set-state! :editor/block-refs #{})
- (if property-block
- (set-editing-block-id! [container-id (:block/uuid property-block) (:block/uuid block)])
- (set-editing-block-id! [container-id (:block/uuid block)]))
- (set-state! :editor/container-id container-id)
- (set-state! :editor/block block)
- (set-state! :editor/content content :path-in-sub-atom (:block/uuid block))
- (set-state! :editor/last-key-code nil)
- (set-state! :editor/set-timestamp-block nil)
- (set-state! :editor/cursor-range cursor-range)
- (when (= :code (:logseq.property.node/display-type (d/entity db (:db/id block))))
- (pub-event! [:editor/focus-code-editor block block-element]))
- (when-let [input (gdom/getElement edit-input-id)]
- (let [pos (count cursor-range)]
- (when content
- (util/set-change-value input content))
- (when (and move-cursor? (not (block-component-editing?)))
- (cursor/move-cursor-to input pos))
- (when (or (util/mobile?) (mobile-util/native-platform?))
- (set-state! :mobile/show-action-bar? false))))))))
- (defn action-bar-open?
- []
- (:mobile/show-action-bar? @state))
- (defn get-git-auto-commit-enabled?
- []
- (false? (sub [:electron/user-cfgs :git/disable-auto-commit?])))
- (defn get-git-commit-on-close-enabled?
- []
- (sub [:electron/user-cfgs :git/commit-on-close?]))
- (defn set-last-key-code!
- [key-code]
- (set-state! :editor/last-key-code key-code))
- (defn get-last-key-code
- []
- @(:editor/last-key-code @state))
- (defn set-ui-last-key-code!
- [key-code]
- (set-state! :ui/global-last-key-code key-code))
- (defn get-ui-last-key-code
- []
- @(:ui/global-last-key-code @state))
- (defn set-block-op-type!
- [op-type]
- (set-state! :editor/block-op-type op-type))
- (defn get-block-op-type
- []
- (:editor/block-op-type @state))
- (defn feature-http-server-enabled?
- []
- (boolean (storage/get ::storage-spec/http-server-enabled)))
- (defn get-plugin-by-id
- [id]
- (when-let [id (and id (keyword id))]
- (get-in @state [:plugin/installed-plugins id])))
- (defn get-enabled?-installed-plugins
- ([theme?] (get-enabled?-installed-plugins theme? true false false))
- ([theme? enabled? include-unpacked? include-all?]
- (filterv
- #(and (if include-unpacked? true (or (:webMode %) (:iir %)))
- (if-not (boolean? enabled?) true (= (not enabled?) (boolean (get-in % [:settings :disabled]))))
- (or include-all? (if (boolean? theme?) (= (boolean theme?) (:theme %)) true)))
- (vals (:plugin/installed-plugins @state)))))
- (defn lsp-enabled?-or-theme
- []
- (:plugin/enabled @state))
- (def lsp-enabled?
- (lsp-enabled?-or-theme))
- (defn consume-updates-from-coming-plugin!
- [payload updated?]
- (when-let [id (keyword (:id payload))]
- (let [prev-pending? (boolean (seq (:plugin/updates-pending @state)))]
- (println "Updates: consumed pending - " id)
- (swap! state update :plugin/updates-pending dissoc id)
- (if updated?
- (if-let [error (:error-code payload)]
- (swap! state update-in [:plugin/updates-coming id] assoc :error-code error)
- (swap! state update :plugin/updates-coming dissoc id))
- (swap! state update :plugin/updates-coming assoc id payload))
- (pub-event! [:plugin/consume-updates id prev-pending? updated?]))))
- (defn coming-update-new-version?
- [pkg]
- (and pkg (:latest-version pkg)))
- (defn plugin-update-available?
- [id]
- (when-let [pkg (and id (get (:plugin/updates-coming @state) (keyword id)))]
- (coming-update-new-version? pkg)))
- (defn all-available-coming-updates
- ([] (all-available-coming-updates (:plugin/updates-coming @state)))
- ([updates] (when-let [updates (vals updates)]
- (filterv #(coming-update-new-version? %) updates))))
- (defn get-next-selected-coming-update
- []
- (when-let [updates (all-available-coming-updates)]
- (let [unchecked (:plugin/updates-unchecked @state)]
- (first (filter #(and (not (and (seq unchecked) (contains? unchecked (:id %))))
- (not (:error-code %))) updates)))))
- (defn set-unchecked-update
- [id unchecked?]
- (swap! state update :plugin/updates-unchecked (if unchecked? conj disj) id))
- (defn reset-unchecked-update
- []
- (swap! state assoc :plugin/updates-unchecked #{}))
- (defn reset-all-updates-state
- []
- (swap! state assoc
- :plugin/updates-auto-checking? false
- :plugin/updates-pending {}
- :plugin/updates-coming {}
- :plugin/updates-downloading? false))
- (defn sub-right-sidebar-blocks
- []
- (when-let [current-repo (get-current-repo)]
- (->> (sub :sidebar/blocks)
- (filter #(= (first %) current-repo)))))
- (defn toggle-collapsed-block!
- [block-id]
- (let [current-repo (get-current-repo)]
- (update-state! [:ui/collapsed-blocks current-repo block-id] not)))
- (defn set-collapsed-block!
- [block-id value]
- (let [current-repo (get-current-repo)]
- (set-state! [:ui/collapsed-blocks current-repo block-id] value)))
- (defn sub-block-collapsed
- [block-id]
- (sub [:ui/collapsed-blocks (get-current-repo) block-id]))
- (defn get-block-collapsed
- [block-id]
- (get-in @state [:ui/collapsed-blocks (get-current-repo) block-id]))
- (defn get-modal-id
- []
- (shui-dialog/get-last-modal-id))
- (defn set-auth-id-token
- [id-token]
- (set-state! :auth/id-token id-token))
- (defn set-auth-refresh-token
- [refresh-token]
- (set-state! :auth/refresh-token refresh-token))
- (defn set-auth-access-token
- [access-token]
- (set-state! :auth/access-token access-token))
- (defn get-auth-id-token []
- (sub :auth/id-token))
- (defn get-auth-refresh-token []
- (:auth/refresh-token @state))
- (defn set-file-sync-manager [graph-uuid v]
- (when (and graph-uuid v)
- (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-manager] v)))
- (defn get-file-sync-manager [graph-uuid]
- (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-manager]))
- (defn clear-file-sync-state! [graph-uuid]
- (set-state! [:file-sync/graph-state graph-uuid] nil))
- (defn clear-file-sync-progress! [graph-uuid]
- (set-state! [:file-sync/graph-state
- graph-uuid
- :file-sync/progress]
- nil))
- (defn set-file-sync-state [graph-uuid v]
- (when v (s/assert :frontend.fs.sync/sync-state v))
- (set-state! [:file-sync/graph-state graph-uuid :file-sync/sync-state] v))
- (defn get-current-file-sync-graph-uuid
- []
- (get-in @state [:file-sync/graph-state :current-graph-uuid]))
- (defn sub-current-file-sync-graph-uuid
- []
- (sub [:file-sync/graph-state :current-graph-uuid]))
- (defn get-file-sync-state
- ([]
- (get-file-sync-state (get-current-file-sync-graph-uuid)))
- ([graph-uuid]
- (get-in @state [:file-sync/graph-state graph-uuid :file-sync/sync-state])))
- (defn sub-file-sync-state
- [graph-uuid]
- (sub [:file-sync/graph-state graph-uuid :file-sync/sync-state]))
- (defn reset-parsing-state!
- []
- (set-state! [:graph/parsing-state (get-current-repo)] {}))
- (defn set-parsing-state!
- [m]
- (update-state! [:graph/parsing-state (get-current-repo)]
- (if (fn? m) m
- (fn [old-value] (merge old-value m)))))
- (defn http-proxy-enabled-or-val? []
- (when-let [{:keys [type protocol host port] :as agent-opts} (sub [:electron/user-cfgs :settings/agent])]
- (when (and (not (contains? #{"system"} type))
- (every? not-empty (vals agent-opts)))
- (str protocol "://" host ":" port))))
- (defn set-mobile-app-state-change
- [is-active?]
- (set-state! :mobile/app-state-change
- {:is-active? is-active?
- :timestamp (inst-ms (js/Date.))}))
- (defn get-sync-graph-by-id
- [graph-uuid]
- (when graph-uuid
- (let [graph (first (filter #(= graph-uuid (:GraphUUID %))
- (get-repos)))]
- (when (:url graph)
- graph))))
- (defn unlinked-dir?
- [dir]
- (contains? (:file/unlinked-dirs @state) dir))
- (defn get-file-rename-event-chan
- []
- (:file/rename-event-chan @state))
- (defn offer-file-rename-event-chan!
- [v]
- {:pre [(map? v)
- (= #{:repo :old-path :new-path} (set (keys v)))]}
- (async/offer! (get-file-rename-event-chan) v))
- (defn set-onboarding-whiteboard!
- [v]
- (set-state! :whiteboard/onboarding-whiteboard? v)
- (storage/set :ls-onboarding-whiteboard? v))
- (defn get-onboarding-whiteboard?
- []
- (get-in @state [:whiteboard/onboarding-whiteboard?]))
- (defn get-local-container-root-url
- []
- (when (mobile-util/native-ios?)
- (get-in @state [:mobile/container-urls :localContainerUrl])))
- (defn get-icloud-container-root-url
- []
- (when (mobile-util/native-ios?)
- (get-in @state [:mobile/container-urls :iCloudContainerUrl])))
- (defn get-current-pdf
- []
- (:pdf/current @state))
- (defn nfs-user-granted?
- [repo]
- (get-in @state [:nfs/user-granted? repo]))
- (defn set-current-pdf!
- [inflated-file]
- (let [settle-file! #(set-state! :pdf/current inflated-file)]
- (if-not (get-current-pdf)
- (settle-file!)
- (when (apply not= (map :identity [inflated-file (get-current-pdf)]))
- (set-state! :pdf/current nil)
- (js/setTimeout #(settle-file!) 16)))))
- (defn focus-whiteboard-shape
- ([shape-id]
- (focus-whiteboard-shape (active-tldraw-app) shape-id))
- ([tln shape-id]
- (when-let [^js api (gobj/get tln "api")]
- (when (and shape-id (parse-uuid shape-id))
- (. api selectShapes shape-id)
- (. api zoomToSelection)))))
- (defn set-user-info!
- [info]
- (when info
- (set-state! :user/info info)
- (let [groups (:UserGroups info)]
- (when (seq groups)
- (storage/set :user-groups groups)))))
- (defn get-user-info []
- (sub :user/info))
- (defn clear-user-info!
- []
- (storage/remove :user-groups))
- (defn set-color-accent! [color]
- (swap! state assoc :ui/radix-color color)
- (storage/set :ui/radix-color color)
- (util/set-android-theme))
- (defn set-editor-font! [font]
- (let [font (if (keyword? font) (name font) (str font))]
- (swap! state assoc :ui/editor-font font)
- (storage/set :ui/editor-font font)))
- (defn handbook-open?
- []
- (:ui/handbooks-open? @state))
- (defn get-handbook-route-chan
- []
- (:handbook/route-chan @state))
- (defn open-handbook-pane!
- [k]
- (when-not (handbook-open?)
- (set-state! :ui/handbooks-open? true))
- (js/setTimeout #(async/go
- (>! (get-handbook-route-chan) k))))
- (defn update-favorites-updated!
- []
- (update-state! :favorites/updated? inc))
- (def get-worker-next-request-id db-transact/get-next-request-id)
- (def add-worker-request! db-transact/add-request!)
- (defn get-next-container-id
- []
- (swap! (:ui/container-id @state) inc))
- (defn get-container-id
- "Either cached container-id or a new id"
- [key]
- (if (seq key)
- (or (get @(:ui/cached-key->container-id @state) key)
- (let [id (get-next-container-id)]
- (swap! (:ui/cached-key->container-id @state) assoc key id)
- id))
- (get-next-container-id)))
- (defn get-current-editor-container-id
- []
- @(:editor/container-id @state))
- (comment
- (defn remove-container-key!
- [key]
- (swap! (:ui/cached-key->container-id @state) dissoc key)))
- (defn get-editor-info
- []
- (when-let [edit-block (get-edit-block)]
- {:block-uuid (:block/uuid edit-block)
- :container-id (or @(:editor/container-id @state) :unknown-container)
- :start-pos @(:editor/start-pos @state)
- :end-pos (get-edit-pos)}))
- (defn conj-block-ref!
- [ref-entity]
- (let [refs! (:editor/block-refs @state)]
- (swap! refs! conj ref-entity)))
- (defn get-highlight-recent-days
- []
- @(:ui/highlight-recent-days @state))
- (defn set-highlight-recent-days!
- [days]
- (prn :debug :set :days days)
- (reset! (:ui/highlight-recent-days @state) days)
- (storage/set :ui/highlight-recent-days days))
- (defn set-rtc-enabled!
- [value]
- (storage/set :logseq-rtc-enabled value)
- (set-state! :feature/enable-rtc? value))
|