mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge branch 'feat/db' into refactor/page-parent
This commit is contained in:
@@ -13,12 +13,12 @@
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.plugin :as plugin-handler]
|
||||
[frontend.handler.property.file :as property-file]
|
||||
[frontend.util.ref :as ref]
|
||||
[frontend.search :as search]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.util.cursor :as cursor]
|
||||
[frontend.util.file-based.priority :as priority]
|
||||
[frontend.util.ref :as ref]
|
||||
[goog.dom :as gdom]
|
||||
[goog.object :as gobj]
|
||||
[logseq.common.config :as common-config]
|
||||
@@ -439,11 +439,10 @@
|
||||
(println "draw file created, " path))
|
||||
text)) "Draw a graph with Excalidraw"])
|
||||
|
||||
(when (util/electron?)
|
||||
["Upload an asset"
|
||||
[[:editor/click-hidden-file-input :id]]
|
||||
"Upload file types like image, pdf, docx, etc.)"
|
||||
:icon/upload])
|
||||
["Upload an asset"
|
||||
[[:editor/click-hidden-file-input :id]]
|
||||
"Upload file types like image, pdf, docx, etc.)"
|
||||
:icon/upload]
|
||||
|
||||
["Template" [[:editor/input command-trigger nil]
|
||||
[:editor/search-template]] "Insert a created template here"
|
||||
@@ -473,7 +472,7 @@
|
||||
commands)
|
||||
|
||||
;; Allow user to modify or extend, should specify how to extend.
|
||||
|
||||
|
||||
(state/get-commands)
|
||||
(when-let [plugin-commands (seq (some->> (state/get-plugins-slash-commands)
|
||||
(mapv #(vec (concat % [nil :icon/puzzle])))))]
|
||||
|
||||
@@ -29,27 +29,6 @@
|
||||
:else
|
||||
content))
|
||||
|
||||
(defn- recur-replace-uuid-in-block-title
|
||||
"Return block-title"
|
||||
[ent max-depth]
|
||||
(let [ref-set (loop [result-refs (:block/refs ent)
|
||||
current-refs (:block/refs ent)
|
||||
depth 0]
|
||||
(if (or (>= depth max-depth) (empty? current-refs))
|
||||
result-refs
|
||||
(let [next-refs (set (mapcat :block/refs current-refs))
|
||||
result-refs' (apply conj result-refs next-refs)]
|
||||
(if (= (count result-refs') (count result-refs))
|
||||
result-refs
|
||||
(recur (apply conj result-refs next-refs) next-refs (inc depth))))))]
|
||||
(loop [result (db-content/id-ref->title-ref (:block/title ent) ref-set true)
|
||||
last-result nil
|
||||
depth 0]
|
||||
(if (or (>= depth max-depth)
|
||||
(= last-result result))
|
||||
result
|
||||
(recur (db-content/id-ref->title-ref result ref-set true) result (inc depth))))))
|
||||
|
||||
(defn- transform-content
|
||||
[repo db {:block/keys [collapsed? format pre-block? title page properties] :as b} level {:keys [heading-to-list?]} context]
|
||||
(let [db-based? (sqlite-util/db-based-graph? repo)
|
||||
@@ -60,7 +39,7 @@
|
||||
markdown? (= :markdown format)
|
||||
title (if db-based?
|
||||
;; replace [[uuid]] with block's content
|
||||
(recur-replace-uuid-in-block-title (d/entity db (:db/id b)) 10)
|
||||
(db-content/recur-replace-uuid-in-block-title (d/entity db (:db/id b)))
|
||||
title)
|
||||
content (or title "")
|
||||
page-first-child? (= (:db/id b) (ldb/get-first-child db (:db/id page)))
|
||||
|
||||
@@ -656,7 +656,7 @@
|
||||
|
||||
All page-names are sanitized except page-name-in-block"
|
||||
[state
|
||||
{:keys [contents-page? whiteboard-page? html-export? other-position? show-unique-title? stop-click-event?
|
||||
{:keys [contents-page? whiteboard-page? other-position? show-unique-title? stop-click-event?
|
||||
on-context-menu]
|
||||
:or {stop-click-event? true}
|
||||
:as config}
|
||||
@@ -701,12 +701,13 @@
|
||||
(reset! *mouse-down? true))))
|
||||
:on-pointer-up (fn [e]
|
||||
(when @*mouse-down?
|
||||
(util/stop e)
|
||||
(state/clear-edit!)
|
||||
(when-not (or (:disable-click? config)
|
||||
(:disable-redirect? config))
|
||||
(when-not (:disable-click? config)
|
||||
(open-page-ref config page-entity e page-name contents-page?))
|
||||
(reset! *mouse-down? false)))
|
||||
:on-key-up (fn [e] (when (and e (= (.-key e) "Enter") (not other-position?))
|
||||
(util/stop e)
|
||||
(state/clear-edit!)
|
||||
(open-page-ref config page-entity e page-name contents-page?)))}
|
||||
on-context-menu
|
||||
@@ -726,7 +727,7 @@
|
||||
(last child)
|
||||
(let [{:keys [content children]} (last child)
|
||||
page-name (subs content 2 (- (count content) 2))]
|
||||
(rum/with-key (page-reference html-export? page-name (assoc config :children children) nil) page-name))))
|
||||
(rum/with-key (page-reference (assoc config :children children) page-name nil) page-name))))
|
||||
(let [page-component (cond
|
||||
(and label
|
||||
(string? label)
|
||||
@@ -943,26 +944,22 @@
|
||||
config (assoc config :block entity)]
|
||||
(cond
|
||||
entity
|
||||
(if (or (ldb/page? entity) (not (:block/page entity)))
|
||||
(let [page-name (some-> (:block/title entity) util/page-name-sanity-lc)
|
||||
whiteboard-page? (model/whiteboard-page? entity)
|
||||
inner (page-inner (assoc config :whiteboard-page? whiteboard-page?) entity children label)
|
||||
modal? (shui-dialog/has-modal?)]
|
||||
(if (and (not (util/mobile?))
|
||||
(not= page-name (:id config))
|
||||
(not (false? preview?))
|
||||
(not disable-preview?)
|
||||
(not modal?))
|
||||
(page-preview-trigger (assoc config :children inner) entity)
|
||||
inner))
|
||||
(block-reference config (:block/uuid entity)
|
||||
(if (string? label)
|
||||
(gp-mldoc/inline->edn label (mldoc/get-default-config :markdown))
|
||||
label)))
|
||||
(let [page-name (some-> (:block/title entity) util/page-name-sanity-lc)
|
||||
whiteboard-page? (model/whiteboard-page? entity)
|
||||
inner (page-inner (assoc config :whiteboard-page? whiteboard-page?) entity children label)
|
||||
modal? (shui-dialog/has-modal?)]
|
||||
(if (and (not (util/mobile?))
|
||||
(not= page-name (:id config))
|
||||
(not (false? preview?))
|
||||
(not disable-preview?)
|
||||
(not modal?))
|
||||
(page-preview-trigger (assoc config :children inner) entity)
|
||||
inner))
|
||||
|
||||
(and (:block/name page) show-non-exists-page?)
|
||||
(page-inner config (merge
|
||||
{:block/title (:block/name page)
|
||||
{:block/title (or (:block/title page)
|
||||
(:block/name page))
|
||||
:block/name (:block/name page)}
|
||||
page) children label)
|
||||
|
||||
@@ -977,8 +974,9 @@
|
||||
|
||||
(rum/defc page-cp
|
||||
[config page]
|
||||
(rum/with-key (page-cp-inner config page)
|
||||
(or (str (:db/id page)) (str (:block/uuid page)) (:block/name page))))
|
||||
(let [id (or (:db/id page) (:block/uuid page) (:block/name page))]
|
||||
(rum/with-key (page-cp-inner config page)
|
||||
(str id))))
|
||||
|
||||
(rum/defc asset-reference
|
||||
[config title path]
|
||||
@@ -1068,58 +1066,62 @@
|
||||
(declare block-positioned-properties)
|
||||
(rum/defc page-reference < rum/reactive db-mixins/query
|
||||
"Component for page reference"
|
||||
[html-export? uuid-or-title* {:keys [nested-link? show-brackets? id] :as config} label]
|
||||
[{:keys [html-export? nested-link? show-brackets? id] :as config*} uuid-or-title* label]
|
||||
(when uuid-or-title*
|
||||
(let [uuid-or-title (if (string? uuid-or-title*)
|
||||
(string/trim uuid-or-title*)
|
||||
(let [str-id (string/trim uuid-or-title*)]
|
||||
(if (util/uuid-string? str-id)
|
||||
(parse-uuid str-id)
|
||||
str-id))
|
||||
uuid-or-title*)
|
||||
show-brackets? (if (some? show-brackets?) show-brackets? (state/show-brackets?))
|
||||
contents-page? (= "contents" (string/lower-case (str id)))
|
||||
block* (db/get-page uuid-or-title)
|
||||
block (or (some-> (:db/id block*) db/sub-block) block*)
|
||||
config' (assoc config
|
||||
:label (mldoc/plain->text label)
|
||||
:contents-page? contents-page?
|
||||
:show-icon? true?)
|
||||
asset? (some? (:logseq.property.asset/type block))
|
||||
page? (ldb/page? block)
|
||||
brackets? (and (or show-brackets? nested-link?)
|
||||
(not html-export?)
|
||||
(not contents-page?)
|
||||
page?)]
|
||||
(when-not (= (:db/id block) (:db/id (:block config)))
|
||||
(cond
|
||||
(and asset? (img-audio-video? block))
|
||||
(asset-cp config block)
|
||||
self-reference? (when (set? (:ref-set config*))
|
||||
(contains? (:ref-set config*) uuid-or-title))]
|
||||
(when-not self-reference?
|
||||
(let [config (update config* :ref-set (fn [s]
|
||||
(let [bid (:block/uuid (:block config*))]
|
||||
(if (nil? s)
|
||||
#{bid}
|
||||
(conj s bid uuid-or-title)))))
|
||||
show-brackets? (if (some? show-brackets?) show-brackets? (state/show-brackets?))
|
||||
contents-page? (= "contents" (string/lower-case (str id)))
|
||||
block* (db/get-page uuid-or-title)
|
||||
block (or (some-> (:db/id block*) db/sub-block) block*)
|
||||
config' (assoc config
|
||||
:label (mldoc/plain->text label)
|
||||
:contents-page? contents-page?
|
||||
:show-icon? true?)
|
||||
asset? (some? (:logseq.property.asset/type block))
|
||||
brackets? (and (or show-brackets? nested-link?)
|
||||
(not html-export?)
|
||||
(not contents-page?))]
|
||||
(when-not (= (:db/id block) (:db/id (:block config)))
|
||||
(cond
|
||||
(and asset? (img-audio-video? block))
|
||||
(asset-cp config block)
|
||||
|
||||
(or page? (:block/tags block))
|
||||
[:span.page-reference
|
||||
{:data-ref (str uuid-or-title)}
|
||||
(when brackets?
|
||||
[:span.text-gray-500.bracket page-ref/left-brackets])
|
||||
(when (and (config/db-based-graph?) (ldb/class-instance? (db/entity :logseq.class/Task) block))
|
||||
[:div.inline-block
|
||||
{:style {:margin-right 1
|
||||
:margin-top -2
|
||||
:vertical-align "middle"}
|
||||
:on-pointer-down (fn [e]
|
||||
(util/stop e))}
|
||||
(block-positioned-properties config block :block-left)])
|
||||
(page-cp config' (if (uuid? uuid-or-title)
|
||||
{:block/uuid uuid-or-title}
|
||||
{:block/name uuid-or-title}))
|
||||
(when brackets?
|
||||
[:span.text-gray-500.bracket page-ref/right-brackets])]
|
||||
(and (string? uuid-or-title) (string/ends-with? uuid-or-title ".excalidraw"))
|
||||
[:div.draw {:on-click (fn [e]
|
||||
(.stopPropagation e))}
|
||||
(excalidraw uuid-or-title (:block/uuid config))]
|
||||
|
||||
(and (string? uuid-or-title) (string/ends-with? uuid-or-title ".excalidraw"))
|
||||
[:div.draw {:on-click (fn [e]
|
||||
(.stopPropagation e))}
|
||||
(excalidraw uuid-or-title (:block/uuid config))]
|
||||
|
||||
:else
|
||||
(page-cp config' (if (uuid? uuid-or-title)
|
||||
{:block/uuid uuid-or-title}
|
||||
{:block/name uuid-or-title})))))))
|
||||
:else
|
||||
[:span.page-reference
|
||||
{:data-ref (str uuid-or-title)}
|
||||
(when brackets?
|
||||
[:span.text-gray-500.bracket page-ref/left-brackets])
|
||||
(when (and (config/db-based-graph?) (ldb/class-instance? (db/entity :logseq.class/Task) block))
|
||||
[:div.inline-block
|
||||
{:style {:margin-right 1
|
||||
:margin-top -2
|
||||
:vertical-align "middle"}
|
||||
:on-pointer-down (fn [e]
|
||||
(util/stop e))}
|
||||
(block-positioned-properties config block :block-left)])
|
||||
(page-cp config' (if (uuid? uuid-or-title)
|
||||
{:block/uuid uuid-or-title}
|
||||
{:block/name uuid-or-title}))
|
||||
(when brackets?
|
||||
[:span.text-gray-500.bracket page-ref/right-brackets])])))))))
|
||||
|
||||
(defn- latex-environment-content
|
||||
[name option content]
|
||||
@@ -1340,13 +1342,18 @@
|
||||
(set-block! block)))
|
||||
[])
|
||||
(when-not self-reference?
|
||||
(if block
|
||||
(cond
|
||||
(config/db-based-graph?)
|
||||
(page-reference config block-id label)
|
||||
|
||||
block
|
||||
(let [config' (update config :ref-set (fn [s]
|
||||
(let [bid (:block/uuid (:block config))]
|
||||
(if (nil? s)
|
||||
#{bid}
|
||||
(conj s bid block-id)))))]
|
||||
(block-reference-aux config' block label))
|
||||
:else
|
||||
(invalid-node-ref block-id)))))
|
||||
|
||||
(defn- render-macro
|
||||
@@ -1475,7 +1482,7 @@
|
||||
(block-reference config id label))
|
||||
|
||||
(not (string/includes? s "."))
|
||||
(page-reference (:html-export? config) s config label)
|
||||
(page-reference config s label)
|
||||
|
||||
(path/protocol-url? s)
|
||||
(->elem :a {:href s
|
||||
@@ -1507,9 +1514,9 @@
|
||||
(map-inline config label)))
|
||||
|
||||
:else
|
||||
(page-reference (:html-export? config) s config label)))
|
||||
(page-reference config s label)))
|
||||
|
||||
(defn- link-cp [config html-export? link]
|
||||
(defn- link-cp [config link]
|
||||
(let [{:keys [url label title metadata full_text]} link]
|
||||
(match url
|
||||
["Block_ref" id]
|
||||
@@ -1533,7 +1540,7 @@
|
||||
(let [label* (if (seq (mldoc/plain->text label)) label nil)]
|
||||
(if (and (string? page) (string/blank? page))
|
||||
[:span (ref/->page-ref page)]
|
||||
(page-reference (:html-export? config) page config label*)))))
|
||||
(page-reference config page label*)))))
|
||||
|
||||
["Embed_data" src]
|
||||
(image-link config url src nil metadata full_text)
|
||||
@@ -1555,7 +1562,7 @@
|
||||
block (db/entity [:block/uuid id])]
|
||||
(if (:block/pre-block? block)
|
||||
(let [page (:block/page block)]
|
||||
(page-reference html-export? (:block/name page) config label))
|
||||
(page-reference config (:block/name page) label))
|
||||
(block-reference config (:link path) label)))
|
||||
|
||||
(= protocol "file")
|
||||
@@ -1977,7 +1984,7 @@
|
||||
(nested-link config html-export? link)
|
||||
|
||||
["Link" link]
|
||||
(link-cp config html-export? link)
|
||||
(link-cp config link)
|
||||
|
||||
[(:or "Verbatim" "Code") s]
|
||||
[:code s]
|
||||
@@ -2052,7 +2059,6 @@
|
||||
selected? (contains? selected block-id)]
|
||||
(when-not selected?
|
||||
(util/clear-selection!)
|
||||
(state/conj-selection-block! (gdom/getElement block-id) :down)
|
||||
(editor-handler/highlight-block! uuid)))
|
||||
|
||||
(editor-handler/block->data-transfer! uuid event false)
|
||||
@@ -2171,7 +2177,7 @@
|
||||
(reset! *bullet-dragging? true)
|
||||
(util/stop-propagation event)
|
||||
(bullet-drag-start event block uuid block-id))
|
||||
:on-drag-end (fn [_]
|
||||
:on-drag-end (fn [_e]
|
||||
(reset! *bullet-dragging? false))
|
||||
:blockid (str uuid)
|
||||
:class (str (when collapsed? "bullet-closed")
|
||||
@@ -3039,7 +3045,6 @@
|
||||
(block-content config block edit-input-id block-id *show-query?))))
|
||||
|
||||
(rum/defcs ^:large-vars/cleanup-todo block-content-or-editor < rum/reactive
|
||||
(rum/local false ::hover?)
|
||||
[state config {:block/keys [uuid] :as block} {:keys [edit-input-id block-id edit? hide-block-refs-count? refs-count *hide-block-refs? *show-query?]}]
|
||||
(let [format (if (config/db-based-graph? (state/get-current-repo))
|
||||
:markdown
|
||||
@@ -3076,7 +3081,10 @@
|
||||
:format format}
|
||||
edit-input-id
|
||||
config))]
|
||||
[:div.flex.flex-1.w-full.block-content-wrapper {:style {:display "flex"}}
|
||||
[:div.flex.flex-1.w-full.block-content-wrapper
|
||||
{:style {:display "flex"}}
|
||||
(when-let [actions-cp (:page-title-actions-cp config)]
|
||||
(actions-cp block))
|
||||
(block-content-with-error config block edit-input-id block-id *show-query? editor-box)
|
||||
|
||||
(when (and (not hide-block-refs-count?)
|
||||
@@ -3182,7 +3190,6 @@
|
||||
rest)
|
||||
config (assoc config
|
||||
:breadcrumb? true
|
||||
:disable-redirect? true
|
||||
:disable-preview? true
|
||||
:stop-click-event? false)]
|
||||
(when (seq parents)
|
||||
@@ -3615,8 +3622,6 @@
|
||||
|
||||
[:div.flex.flex-col.w-full
|
||||
[:div.block-main-content.flex.flex-row.gap-2
|
||||
(when-let [actions-cp (:page-title-actions-cp config)]
|
||||
(actions-cp block))
|
||||
(when page-icon
|
||||
page-icon)
|
||||
|
||||
|
||||
@@ -524,10 +524,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.block-main-content {
|
||||
.ls-page-title-container .block-content-wrapper {
|
||||
.ls-page-title-actions {
|
||||
@apply absolute -top-4 opacity-0;
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& > .db-page-title-actions {
|
||||
& > .ls-page-title-actions {
|
||||
@apply delay-300 transition-opacity opacity-100;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
(when (seq children)
|
||||
[:ul
|
||||
(for [child (sort-by :block/title children)]
|
||||
(let [title [:li.ml-2 (block/page-reference false (:block/uuid child) {:show-brackets? false} nil)]]
|
||||
(let [title [:li.ml-2 (block/page-reference {:show-brackets? false} (:block/uuid child) nil)]]
|
||||
(if (seq (:logseq.property.class/_extends child))
|
||||
(ui/foldable
|
||||
title
|
||||
|
||||
@@ -933,8 +933,13 @@
|
||||
nil)
|
||||
|
||||
(defn- on-mouse-up
|
||||
[_e]
|
||||
(editor-handler/show-action-bar!))
|
||||
[e]
|
||||
(when-not (or (.closest (.-target e) ".block-control-wrap")
|
||||
(.closest (.-target e) "button")
|
||||
(.closest (.-target e) "input")
|
||||
(.closest (.-target e) "textarea")
|
||||
(.closest (.-target e) "a"))
|
||||
(editor-handler/show-action-bar!)))
|
||||
|
||||
(rum/defcs ^:large-vars/cleanup-todo root-container < rum/reactive
|
||||
(mixins/event-mixin
|
||||
|
||||
@@ -134,6 +134,20 @@
|
||||
:other-attrs {:block/link (:db/id page')}}))))
|
||||
(page-handler/on-chosen-handler input id pos format)))
|
||||
|
||||
(defn- matched-pages-with-new-page [partial-matched-pages db-tag? q]
|
||||
(if (or (db/page-exists? q (if db-tag?
|
||||
#{:logseq.class/Tag}
|
||||
;; Page existence here should be the same as entity-util/page?.
|
||||
;; Don't show 'New page' if a page has any of these tags
|
||||
db-class/page-classes))
|
||||
(and db-tag? (some ldb/class? (:block/_alias (db/get-page q)))))
|
||||
partial-matched-pages
|
||||
(if db-tag?
|
||||
(concat [{:block/title (str (t :new-tag) " " q)}]
|
||||
partial-matched-pages)
|
||||
(cons {:block/title (str (t :new-page) " " q)}
|
||||
partial-matched-pages))))
|
||||
|
||||
(rum/defc page-search-aux
|
||||
[id format embed? db-tag? q current-pos input pos]
|
||||
(let [db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
@@ -157,25 +171,11 @@
|
||||
date/nlp-pages)
|
||||
(take 10))))
|
||||
;; reorder, shortest and starts-with first.
|
||||
(let [matched-pages-with-new-page
|
||||
(fn [partial-matched-pages]
|
||||
(if (or (db/page-exists? q (if db-tag?
|
||||
#{:logseq.class/Tag}
|
||||
;; Page existence here should be the same as entity-util/page?.
|
||||
;; Don't show 'New page' if a page has any of these tags
|
||||
db-class/page-classes))
|
||||
(and db-tag? (some ldb/class? (:block/_alias (db/get-page q)))))
|
||||
partial-matched-pages
|
||||
(if db-tag?
|
||||
(concat [{:block/title (str (t :new-tag) " " q)}]
|
||||
partial-matched-pages)
|
||||
(cons {:block/title (str (t :new-page) " " q)}
|
||||
partial-matched-pages))))]
|
||||
(if (and (seq matched-pages)
|
||||
(gstring/caseInsensitiveStartsWith (:block/title (first matched-pages)) q))
|
||||
(cons (first matched-pages)
|
||||
(matched-pages-with-new-page (rest matched-pages)))
|
||||
(matched-pages-with-new-page matched-pages))))]
|
||||
(if (and (seq matched-pages)
|
||||
(gstring/caseInsensitiveStartsWith (:block/title (first matched-pages)) q))
|
||||
(cons (first matched-pages)
|
||||
(matched-pages-with-new-page (rest matched-pages) db-tag? q))
|
||||
(matched-pages-with-new-page matched-pages db-tag? q)))]
|
||||
[:<>
|
||||
(ui/auto-complete
|
||||
matched-pages'
|
||||
@@ -184,7 +184,9 @@
|
||||
(page-handler/page-not-exists-handler input id q current-pos))
|
||||
:item-render (fn [block _chosen?]
|
||||
(let [block' (if-let [id (:block/uuid block)]
|
||||
(or (db/entity [:block/uuid id]) block)
|
||||
(if-let [e (db/entity [:block/uuid id])]
|
||||
(assoc e :block/title (:block/title block))
|
||||
block)
|
||||
block)]
|
||||
[:div.flex.flex-col
|
||||
(when (and (:block/uuid block') (:block/parent block'))
|
||||
@@ -218,10 +220,11 @@
|
||||
(ui/icon "letter-n" {:size 14}))])
|
||||
|
||||
(let [title (if db-tag?
|
||||
(let [target (first (:block/_alias block'))]
|
||||
(let [target (first (:block/_alias block'))
|
||||
title (:block/title block)]
|
||||
(if (ldb/class? target)
|
||||
(str (:block/title block') " -> alias: " (:block/title target))
|
||||
(:block/title block')))
|
||||
(str title " -> alias: " (:block/title target))
|
||||
title))
|
||||
(block-handler/block-unique-title block'))]
|
||||
(search-handler/highlight-exact-query title q))]]))
|
||||
:empty-placeholder [:div.text-gray-500.text-sm.px-4.py-2 (if db-tag?
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
[frontend.handler.export.opml :as export-opml]
|
||||
[frontend.handler.export.text :as export-text]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.idb :as idb]
|
||||
[frontend.image :as image]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.state :as state]
|
||||
@@ -33,51 +32,55 @@
|
||||
[:div.flex.flex-col.gap-4
|
||||
[:div.font-medium.opacity-50
|
||||
"Schedule backup"]
|
||||
(if backup-folder
|
||||
[:div.flex.flex-row.items-center.gap-1.text-sm
|
||||
[:div.opacity-50 (str "Backup folder:")]
|
||||
backup-folder
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:class "!px-1 !py-1"
|
||||
:title "Change backup folder"
|
||||
:on-click (fn []
|
||||
(p/do!
|
||||
(db/transact! [[:db/retractEntity :logseq.kv/graph-backup-folder]])
|
||||
(reset! *backup-folder nil)))
|
||||
:size :sm}
|
||||
(ui/icon "edit"))]
|
||||
(shui/button
|
||||
{:variant :default
|
||||
:on-click (fn []
|
||||
(p/let [result (utils/openDirectory #js {:mode "readwrite"})
|
||||
handle (first result)
|
||||
folder-name (.-name handle)]
|
||||
(idb/set-item!
|
||||
(str "handle/" (js/btoa repo) "/" folder-name) handle)
|
||||
(db/transact! [(ldb/kv :logseq.kv/graph-backup-folder folder-name)])
|
||||
(reset! *backup-folder folder-name)))}
|
||||
"Set backup folder first"))
|
||||
[:div.opacity-50.text-sm
|
||||
"Backup will be created every hour."]
|
||||
(if (utils/nfsSupported)
|
||||
[:<>
|
||||
(if backup-folder
|
||||
[:div.flex.flex-row.items-center.gap-1.text-sm
|
||||
[:div.opacity-50 (str "Backup folder:")]
|
||||
backup-folder
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:class "!px-1 !py-1"
|
||||
:title "Change backup folder"
|
||||
:on-click (fn []
|
||||
(p/do!
|
||||
(db/transact! [[:db/retractEntity :logseq.kv/graph-backup-folder]])
|
||||
(reset! *backup-folder nil)))
|
||||
:size :sm}
|
||||
(ui/icon "edit"))]
|
||||
(shui/button
|
||||
{:variant :default
|
||||
:on-click (fn []
|
||||
(p/let [[folder-name _handle] (export/choose-backup-folder repo)]
|
||||
(reset! *backup-folder folder-name)))}
|
||||
"Set backup folder first"))
|
||||
[:div.opacity-50.text-sm
|
||||
"Backup will be created every hour."]
|
||||
|
||||
(when backup-folder
|
||||
(shui/button
|
||||
{:variant :default
|
||||
:on-click (fn []
|
||||
(->
|
||||
(p/let [result (export/backup-db-graph repo)]
|
||||
(case result
|
||||
true
|
||||
(notification/show! "Backup successful!" :success)
|
||||
:graph-not-changed
|
||||
(notification/show! "Graph has not been updated since last export." :success)
|
||||
nil)
|
||||
(export/auto-db-backup! repo {:backup-now? false}))
|
||||
(p/catch (fn [error]
|
||||
(println "Failed to backup.")
|
||||
(js/console.error error)))))}
|
||||
"Backup now"))]))
|
||||
(when backup-folder
|
||||
(shui/button
|
||||
{:variant :default
|
||||
:on-click (fn []
|
||||
(->
|
||||
(p/let [result (export/backup-db-graph repo :set-folder)]
|
||||
(case result
|
||||
true
|
||||
(notification/show! "Backup successful!" :success)
|
||||
:graph-not-changed
|
||||
(notification/show! "Graph has not been updated since last export." :success)
|
||||
nil)
|
||||
(export/auto-db-backup! repo {:backup-now? false}))
|
||||
(p/catch (fn [error]
|
||||
(println "Failed to backup.")
|
||||
(js/console.error error)))))}
|
||||
"Backup now"))]
|
||||
[:div
|
||||
[:span "Your browser doesn't support "]
|
||||
[:a
|
||||
{:href "https://developer.chrome.com/docs/capabilities/web-apis/file-system-access"
|
||||
:target "_blank"}
|
||||
"The File System Access API"]
|
||||
[:span ", please switch to a Chromium-based browser."]])]))
|
||||
|
||||
(rum/defc export
|
||||
[]
|
||||
@@ -133,7 +136,7 @@
|
||||
"Export debug transit file"]
|
||||
[:p.text-sm.opacity-70.mb-0 "Any sensitive data will be removed in the exported transit file, you can send it to us for debugging."]])
|
||||
|
||||
(when (and db-based? util/web-platform? (utils/nfsSupported))
|
||||
(when (and db-based? util/web-platform?)
|
||||
[:div
|
||||
[:hr]
|
||||
(auto-backup)])]])))
|
||||
|
||||
@@ -60,10 +60,7 @@
|
||||
(when (and (string? page) page)
|
||||
(let [full-page (->> (take (inc idx) namespace)
|
||||
util/string-join-path)]
|
||||
(block/page-reference false
|
||||
full-page
|
||||
{}
|
||||
page))))
|
||||
(block/page-reference {} full-page page))))
|
||||
(interpose [:span.mx-2.opacity-30 "/"]))])]
|
||||
{:default-collapsed? false
|
||||
:title-trigger? true})])))
|
||||
|
||||
@@ -402,8 +402,10 @@
|
||||
(str "collab-" current-repo))
|
||||
(rtc-indicator/indicator)])
|
||||
|
||||
(when (user-handler/logged-in?)
|
||||
(rtc-indicator/downloading-detail))
|
||||
(when (user-handler/logged-in?)
|
||||
(rtc-indicator/downloading-detail))
|
||||
(when (user-handler/logged-in?)
|
||||
(rtc-indicator/uploading-detail))
|
||||
|
||||
(when (and current-repo
|
||||
(not (config/demo-graph? current-repo))
|
||||
|
||||
@@ -29,9 +29,10 @@
|
||||
opts (dissoc opts :color?)
|
||||
item (cond
|
||||
(and (= :emoji (:type icon')) (:id icon'))
|
||||
[:em-emoji (merge {:id (:id icon')
|
||||
:style {:line-height 1}}
|
||||
opts)]
|
||||
[:span.ui__icon
|
||||
[:em-emoji (merge {:id (:id icon')
|
||||
:style {:line-height 1}}
|
||||
opts)]]
|
||||
|
||||
(and (= :tabler-icon (:type icon')) (:id icon'))
|
||||
(ui/icon (:id icon') opts))]
|
||||
|
||||
@@ -420,11 +420,11 @@
|
||||
|
||||
(rum/defc db-page-title-actions
|
||||
[page]
|
||||
[:div.absolute.-top-4.left-0.opacity-0.db-page-title-actions
|
||||
[:div.ls-page-title-actions
|
||||
[:div.flex.flex-row.items-center.gap-2
|
||||
(when-not (:logseq.property/icon (db/entity (:db/id page)))
|
||||
(shui/button
|
||||
{:variant :outline
|
||||
{:variant :ghost
|
||||
:size :sm
|
||||
:class "px-2 py-0 h-6 text-xs text-muted-foreground"
|
||||
:on-click (fn [e]
|
||||
@@ -434,7 +434,7 @@
|
||||
"Add icon"))
|
||||
|
||||
(shui/button
|
||||
{:variant :outline
|
||||
{:variant :ghost
|
||||
:size :sm
|
||||
:class "px-2 py-0 h-6 text-xs text-muted-foreground"
|
||||
:on-click (fn [e]
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.db-page-title-actions {
|
||||
.ls-page-title-actions {
|
||||
&:has(button[data-popup-active]) {
|
||||
@apply opacity-100;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
[lambdaisland.glogi :as log]
|
||||
[logseq.common.util.macro :as macro-util]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.content :as db-content]
|
||||
[logseq.db.frontend.entity-util :as entity-util]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
[logseq.db.frontend.property.type :as db-property-type]
|
||||
@@ -748,7 +749,7 @@
|
||||
id (:db/id node)
|
||||
[header label] (if (integer? id)
|
||||
(let [node-title (if (seq (:logseq.property/classes property))
|
||||
(:block/title node)
|
||||
(db-content/recur-replace-uuid-in-block-title node)
|
||||
(block-handler/block-unique-title node))
|
||||
title (subs node-title 0 256)
|
||||
node (or (db/entity id) node)
|
||||
@@ -756,7 +757,7 @@
|
||||
header (when-not (db/page? node)
|
||||
(when-let [breadcrumb (state/get-component :block/breadcrumb)]
|
||||
[:div.text-xs.opacity-70
|
||||
(breadcrumb {:search? true} (state/get-current-repo) (:block/uuid block) {})]))
|
||||
(breadcrumb {:search? true} (state/get-current-repo) (:block/uuid node) {})]))
|
||||
label [:div.flex.flex-row.items-center.gap-1
|
||||
(when-not (or (:logseq.property/classes property)
|
||||
(= (:db/ident property) :block/tags))
|
||||
@@ -1092,10 +1093,7 @@
|
||||
(closed-value-item value opts)
|
||||
|
||||
(or (entity-util/page? value)
|
||||
(and (seq (:block/tags value))
|
||||
;; FIXME: page-cp should be renamed to node-cp and
|
||||
;; support this case and maybe other complex cases.
|
||||
(not (string/includes? (:block/title value) "[["))))
|
||||
(seq (:block/tags value)))
|
||||
(when value
|
||||
(let [opts {:disable-preview? true
|
||||
:tag? tag?
|
||||
@@ -1158,7 +1156,7 @@
|
||||
(if editing?
|
||||
(popup-content nil)
|
||||
(let [show! (fn [e]
|
||||
(util/stop e)
|
||||
(state/clear-selection!)
|
||||
(let [target (when e (.-target e))]
|
||||
(when-not (or config/publishing?
|
||||
(util/shift-key? e)
|
||||
@@ -1173,7 +1171,7 @@
|
||||
{:ref *el
|
||||
:id trigger-id
|
||||
:tabIndex 0
|
||||
:on-click show!
|
||||
:on-pointer-down show!
|
||||
:on-key-down (fn [e]
|
||||
(case (util/ekey e)
|
||||
("Backspace" "Delete")
|
||||
|
||||
@@ -38,10 +38,11 @@
|
||||
(rum/defc block-cp < rum/reactive
|
||||
[repo idx block]
|
||||
(let [id (:block/uuid block)]
|
||||
(page/page-cp {:parameters {:path {:name (str id)}}
|
||||
:sidebar? true
|
||||
:sidebar/idx idx
|
||||
:repo repo})))
|
||||
[:div.mt-2
|
||||
(page/page-cp {:parameters {:path {:name (str id)}}
|
||||
:sidebar? true
|
||||
:sidebar/idx idx
|
||||
:repo repo})]))
|
||||
|
||||
(defn get-scrollable-container
|
||||
[]
|
||||
@@ -68,77 +69,89 @@
|
||||
:sidebar-key sidebar-key} repo block-id {:indent? false})]
|
||||
(block-cp repo idx block)]))
|
||||
|
||||
(rum/defc search-title < rum/reactive
|
||||
[*input]
|
||||
(let [input (rum/react *input)
|
||||
input' (if (string/blank? input) "Blank input" input)]
|
||||
[:span.overflow-hidden.text-ellipsis input']))
|
||||
|
||||
(rum/defc sidebar-search
|
||||
[repo block-type init-key input *input]
|
||||
(rum/with-key
|
||||
(cmdk/cmdk-block {:initial-input input
|
||||
:sidebar? true
|
||||
:on-input-change (fn [new-value]
|
||||
(reset! *input new-value))
|
||||
:on-input-blur (fn [new-value]
|
||||
(state/sidebar-replace-block! [repo input block-type]
|
||||
[repo new-value block-type]))})
|
||||
(str init-key)))
|
||||
|
||||
(defn- <build-sidebar-item
|
||||
[repo idx db-id block-type *db-id init-key]
|
||||
(p/do!
|
||||
(db-async/<get-block repo db-id)
|
||||
(let [lookup (cond
|
||||
(integer? db-id) db-id
|
||||
(uuid? db-id) [:block/uuid db-id]
|
||||
:else nil)
|
||||
entity (when lookup (db/entity repo lookup))
|
||||
page? (ldb/page? entity)
|
||||
block-render (fn []
|
||||
(when entity
|
||||
(if page?
|
||||
[[:.flex.items-center.page-title.gap-1
|
||||
(icon/get-node-icon-cp entity {:class "text-md"})
|
||||
[:span.overflow-hidden.text-ellipsis (:block/title entity)]]
|
||||
(page-cp repo (str (:block/uuid entity)))]
|
||||
(block-with-breadcrumb repo entity idx [repo db-id block-type] false))))]
|
||||
(case (keyword block-type)
|
||||
:contents
|
||||
(when-let [page (db/get-page "Contents")]
|
||||
[[:.flex.items-center (ui/icon "list-details" {:class "text-md mr-2"}) (t :right-side-bar/contents)]
|
||||
(page-cp repo (str (:block/uuid page)))])
|
||||
(->
|
||||
(p/do!
|
||||
(when-not (contains? #{:contents :search} block-type)
|
||||
(db-async/<get-block repo db-id))
|
||||
(let [lookup (cond
|
||||
(integer? db-id) db-id
|
||||
(uuid? db-id) [:block/uuid db-id]
|
||||
:else nil)
|
||||
entity (when lookup (db/entity repo lookup))
|
||||
page? (ldb/page? entity)
|
||||
block-render (fn []
|
||||
(when entity
|
||||
(if page?
|
||||
[[:.flex.items-center.page-title.gap-1
|
||||
(icon/get-node-icon-cp entity {:class "text-md"})
|
||||
[:span.overflow-hidden.text-ellipsis (:block/title entity)]]
|
||||
(page-cp repo (str (:block/uuid entity)))]
|
||||
(block-with-breadcrumb repo entity idx [repo db-id block-type] false))))]
|
||||
(case (keyword block-type)
|
||||
:contents
|
||||
(when-let [page (db/get-page "Contents")]
|
||||
[[:.flex.items-center (ui/icon "list-details" {:class "text-md mr-2"}) (t :right-side-bar/contents)]
|
||||
(page-cp repo (str (:block/uuid page)))])
|
||||
|
||||
:help
|
||||
[[:.flex.items-center (ui/icon "help" {:class "text-md mr-2"}) (t :right-side-bar/help)] (onboarding/help)]
|
||||
:help
|
||||
[[:.flex.items-center (ui/icon "help" {:class "text-md mr-2"}) (t :right-side-bar/help)] (onboarding/help)]
|
||||
|
||||
:page-graph
|
||||
[[:.flex.items-center (ui/icon "hierarchy" {:class "text-md mr-2"}) (t :right-side-bar/page-graph)]
|
||||
(page/page-graph)]
|
||||
:page-graph
|
||||
[[:.flex.items-center (ui/icon "hierarchy" {:class "text-md mr-2"}) (t :right-side-bar/page-graph)]
|
||||
(page/page-graph)]
|
||||
|
||||
:block-ref
|
||||
(let [lookup (if (integer? db-id) db-id [:block/uuid db-id])]
|
||||
(when-let [block (db/entity repo lookup)]
|
||||
[(t :right-side-bar/block-ref)
|
||||
(block-with-breadcrumb repo block idx [repo db-id block-type] true)]))
|
||||
:block-ref
|
||||
(let [lookup (if (integer? db-id) db-id [:block/uuid db-id])]
|
||||
(when-let [block (db/entity repo lookup)]
|
||||
[(t :right-side-bar/block-ref)
|
||||
(block-with-breadcrumb repo block idx [repo db-id block-type] true)]))
|
||||
|
||||
:block
|
||||
(block-render)
|
||||
:block
|
||||
(block-render)
|
||||
|
||||
:page
|
||||
(block-render)
|
||||
:page
|
||||
(block-render)
|
||||
|
||||
:search
|
||||
[[:.flex.items-center.page-title
|
||||
(ui/icon "search" {:class "text-md mr-2"})
|
||||
(let [input (rum/react *db-id)
|
||||
input' (if (string/blank? input) "Blank input" input)]
|
||||
[:span.overflow-hidden.text-ellipsis input'])]
|
||||
(rum/with-key
|
||||
(cmdk/cmdk-block {:initial-input db-id
|
||||
:sidebar? true
|
||||
:on-input-change (fn [new-value]
|
||||
(reset! *db-id new-value))
|
||||
:on-input-blur (fn [new-value]
|
||||
(state/sidebar-replace-block! [repo db-id block-type]
|
||||
[repo new-value block-type]))})
|
||||
(str init-key))]
|
||||
:search
|
||||
[[:.flex.items-center.page-title
|
||||
(ui/icon "search" {:class "text-md mr-2"})
|
||||
(search-title *db-id)]
|
||||
(sidebar-search repo block-type init-key db-id *db-id)]
|
||||
|
||||
:shortcut-settings
|
||||
[[:.flex.items-center (ui/icon "command" {:class "text-md mr-2"}) (t :help/shortcuts)]
|
||||
(shortcut-settings)]
|
||||
:rtc
|
||||
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) RTC"]
|
||||
(rtc-debug-ui/rtc-debug-ui)]
|
||||
:shortcut-settings
|
||||
[[:.flex.items-center (ui/icon "command" {:class "text-md mr-2"}) (t :help/shortcuts)]
|
||||
(shortcut-settings)]
|
||||
:rtc
|
||||
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) RTC"]
|
||||
(rtc-debug-ui/rtc-debug-ui)]
|
||||
|
||||
:profiler
|
||||
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) Profiler"]
|
||||
(profiler/profiler)]
|
||||
:profiler
|
||||
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) Profiler"]
|
||||
(profiler/profiler)]
|
||||
|
||||
["" [:span]]))))
|
||||
["" [:span]])))
|
||||
(p/catch (fn [error]
|
||||
(js/console.error error)))))
|
||||
|
||||
(defonce *drag-to
|
||||
(atom nil))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns frontend.components.rtc.indicator
|
||||
"RTC state indicator"
|
||||
(:require [cljs-time.core :as t]
|
||||
[clojure.pprint :as pprint]
|
||||
(:require [clojure.pprint :as pprint]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[frontend.db :as db]
|
||||
[frontend.flows :as flows]
|
||||
@@ -138,19 +137,25 @@
|
||||
pprint/pprint
|
||||
with-out-str)]])]))
|
||||
|
||||
(defn- downloading?
|
||||
[detail-info]
|
||||
(when-let [{:keys [created-at sub-type]} (first (:download-logs detail-info))]
|
||||
(and (not= :download-completed sub-type)
|
||||
(> 600 ;; 10min
|
||||
(/ (- (t/now) created-at) 1000)))))
|
||||
|
||||
(defn- uploading?
|
||||
[detail-info]
|
||||
(when-let [{:keys [created-at sub-type]} (first (:upload-logs detail-info))]
|
||||
(and (not= :upload-completed sub-type)
|
||||
(> 600
|
||||
(/ (- (t/now) created-at) 1000)))))
|
||||
(rum/defc indicator
|
||||
[]
|
||||
(let [detail-info (hooks/use-flow-state (m/watch *detail-info))
|
||||
_ (hooks/use-flow-state flows/current-login-user-flow)
|
||||
online? (hooks/use-flow-state flows/network-online-event-flow)
|
||||
rtc-state (:rtc-state detail-info)
|
||||
unpushed-block-update-count (:pending-local-ops detail-info)
|
||||
{:keys [local-tx remote-tx]} detail-info]
|
||||
[:div.cp__rtc-sync
|
||||
[:div.hidden {"data-testid" "rtc-tx"} (pr-str {:local-tx local-tx :remote-tx remote-tx})]
|
||||
[:div.cp__rtc-sync-indicator.flex.flex-row.items-center.gap-1
|
||||
(shui/button-ghost-icon :cloud
|
||||
{:on-click #(shui/popup-show! (.-target %)
|
||||
(details online?)
|
||||
{:align "end"})
|
||||
:class (util/classnames [{:cloud true
|
||||
:on (and online? (= :open rtc-state))
|
||||
:idle (and online? (= :open rtc-state) (zero? unpushed-block-update-count))
|
||||
:queuing (pos? unpushed-block-update-count)}])})]]))
|
||||
|
||||
(def ^:private *accumulated-download-logs (atom []))
|
||||
(c.m/run-background-task
|
||||
@@ -163,6 +168,17 @@
|
||||
(swap! *accumulated-download-logs (fn [logs] (take 20 (conj logs log)))))))
|
||||
rtc-flows/rtc-download-log-flow))
|
||||
|
||||
(def ^:private *accumulated-upload-logs (atom []))
|
||||
(c.m/run-background-task
|
||||
::update-accumulated-upload-logs
|
||||
(m/reduce
|
||||
(fn [_ log]
|
||||
(when log
|
||||
(if (= :upload-completed (:sub-type log))
|
||||
(reset! *accumulated-upload-logs [])
|
||||
(swap! *accumulated-upload-logs (fn [logs] (take 20 (conj logs log)))))))
|
||||
rtc-flows/rtc-upload-log-flow))
|
||||
|
||||
(defn- accumulated-logs-flow
|
||||
[*acc-logs]
|
||||
(->> (m/watch *acc-logs)
|
||||
@@ -181,39 +197,14 @@
|
||||
(for [log download-logs]
|
||||
[:div (:message log)])])))
|
||||
|
||||
(rum/defc indicator
|
||||
(rum/defc uploading-logs
|
||||
[]
|
||||
(let [detail-info (hooks/use-flow-state (m/watch *detail-info))
|
||||
_ (hooks/use-flow-state flows/current-login-user-flow)
|
||||
online? (hooks/use-flow-state flows/network-online-event-flow)
|
||||
uploading?' (uploading? detail-info)
|
||||
downloading?' (downloading? detail-info)
|
||||
rtc-state (:rtc-state detail-info)
|
||||
unpushed-block-update-count (:pending-local-ops detail-info)
|
||||
{:keys [local-tx remote-tx]} detail-info]
|
||||
[:div.cp__rtc-sync
|
||||
[:div.hidden {"data-testid" "rtc-tx"} (pr-str {:local-tx local-tx :remote-tx remote-tx})]
|
||||
[:div.cp__rtc-sync-indicator.flex.flex-row.items-center.gap-1
|
||||
(when downloading?'
|
||||
(shui/button
|
||||
{:class "opacity-50"
|
||||
:variant :ghost
|
||||
:size :sm}
|
||||
"Downloading..."))
|
||||
(when uploading?'
|
||||
(shui/button
|
||||
{:class "opacity-50"
|
||||
:variant :ghost
|
||||
:size :sm}
|
||||
"Uploading..."))
|
||||
(shui/button-ghost-icon :cloud
|
||||
{:on-click #(shui/popup-show! (.-target %)
|
||||
(details online?)
|
||||
{:align "end"})
|
||||
:class (util/classnames [{:cloud true
|
||||
:on (and online? (= :open rtc-state))
|
||||
:idle (and online? (= :open rtc-state) (zero? unpushed-block-update-count))
|
||||
:queuing (pos? unpushed-block-update-count)}])})]]))
|
||||
(let [upload-logs-flow (accumulated-logs-flow *accumulated-upload-logs)
|
||||
upload-logs (hooks/use-flow-state upload-logs-flow)]
|
||||
(when (seq upload-logs)
|
||||
[:div
|
||||
(for [log upload-logs]
|
||||
[:div (:message log)])])))
|
||||
|
||||
(def ^:private downloading?-flow
|
||||
(->> rtc-flows/rtc-download-log-flow
|
||||
@@ -231,3 +222,20 @@
|
||||
(downloading-logs)
|
||||
{:align "end"})}
|
||||
"Downloading...")))
|
||||
|
||||
(def ^:private upload?-flow
|
||||
(->> rtc-flows/rtc-upload-log-flow
|
||||
(m/eduction (map (fn [log] (not= :upload-completed (:sub-type log)))))
|
||||
(c.m/continue-flow false)))
|
||||
|
||||
(rum/defc uploading-detail
|
||||
[]
|
||||
(when (true? (hooks/use-flow-state upload?-flow))
|
||||
(shui/button
|
||||
{:class "opacity-50"
|
||||
:variant :ghost
|
||||
:size :sm
|
||||
:on-click #(shui/popup-show! (.-target %)
|
||||
(uploading-logs)
|
||||
{:align "end"})}
|
||||
"Uploading...")))
|
||||
|
||||
@@ -99,7 +99,7 @@ independent of format as format specific heading characters are stripped"
|
||||
(let [block (db-utils/entity repo block-id)
|
||||
ref-tags (distinct (concat (:block/tags block) (:block/refs block)))]
|
||||
(= (-> block-content
|
||||
(db-content/id-ref->title-ref ref-tags true)
|
||||
(db-content/id-ref->title-ref ref-tags)
|
||||
(db-content/content-id-ref->page ref-tags)
|
||||
heading-content->route-name)
|
||||
(string/lower-case external-content))))
|
||||
|
||||
@@ -1252,15 +1252,22 @@
|
||||
|
||||
(defonce *action-bar-timeout (atom nil))
|
||||
|
||||
(defn popup-exists?
|
||||
[id]
|
||||
(some->> (shui-popup/get-popups)
|
||||
(some #(some-> % (:id) (str) (string/includes? (str id))))))
|
||||
|
||||
(defn show-action-bar!
|
||||
[& {:keys [delay]
|
||||
:or {delay 200}}]
|
||||
(when (config/db-based-graph?)
|
||||
(when (and (config/db-based-graph?) (not (popup-exists? :selection-action-bar)))
|
||||
(when-let [timeout @*action-bar-timeout]
|
||||
(js/clearTimeout timeout))
|
||||
(state/pub-event! [:editor/hide-action-bar])
|
||||
(let [timeout (js/setTimeout #(state/pub-event! [:editor/show-action-bar]) delay)]
|
||||
(reset! *action-bar-timeout timeout))))
|
||||
(when (seq (remove (fn [b] (dom/has-class? b "ls-table-cell"))
|
||||
(state/get-selection-blocks)))
|
||||
(let [timeout (js/setTimeout #(state/pub-event! [:editor/show-action-bar]) delay)]
|
||||
(reset! *action-bar-timeout timeout)))))
|
||||
|
||||
(defn- select-block-up-down
|
||||
[direction]
|
||||
@@ -3333,11 +3340,6 @@
|
||||
(cursor/select-up-down input direction anchor cursor-rect)))
|
||||
(select-block-up-down direction))))
|
||||
|
||||
(defn popup-exists?
|
||||
[id]
|
||||
(some->> (shui-popup/get-popups)
|
||||
(some #(some-> % (:id) (str) (string/includes? (str id))))))
|
||||
|
||||
(defn editor-commands-popup-exists?
|
||||
[]
|
||||
(popup-exists? "editor.commands"))
|
||||
|
||||
@@ -196,14 +196,15 @@
|
||||
|
||||
(defmethod handle :capture-error [[_ {:keys [error payload]}]]
|
||||
(let [[user-uuid graph-uuid tx-id] @sync/graphs-txid
|
||||
payload (assoc payload
|
||||
:user-id user-uuid
|
||||
:graph-id graph-uuid
|
||||
:tx-id tx-id
|
||||
:db-based (config/db-based-graph? (state/get-current-repo))
|
||||
:schema-version (str db-schema/version)
|
||||
:db-schema-version (when-let [db (frontend.db/get-db)]
|
||||
(str (:kv/value (frontend.db/entity db :logseq.kv/schema-version)))))]
|
||||
payload (merge
|
||||
{:schema-version (str db-schema/version)
|
||||
:db-schema-version (when-let [db (frontend.db/get-db)]
|
||||
(str (:kv/value (frontend.db/entity db :logseq.kv/schema-version))))
|
||||
:user-id user-uuid
|
||||
:graph-id graph-uuid
|
||||
:tx-id tx-id
|
||||
:db-based (config/db-based-graph? (state/get-current-repo))}
|
||||
payload)]
|
||||
(Sentry/captureException error
|
||||
(bean/->js {:tags payload}))))
|
||||
|
||||
|
||||
@@ -250,11 +250,33 @@
|
||||
(.remove (.-handle file))))
|
||||
old-versioned-files)))
|
||||
|
||||
(defn backup-db-graph
|
||||
(defn choose-backup-folder
|
||||
[repo]
|
||||
(p/let [result (utils/openDirectory #js {:mode "readwrite"})
|
||||
handle (first result)
|
||||
folder-name (.-name handle)]
|
||||
(js/console.dir handle)
|
||||
(idb/set-item!
|
||||
(str "handle/" (js/btoa repo) "/" folder-name) handle)
|
||||
(db/transact! [(ldb/kv :logseq.kv/graph-backup-folder folder-name)])
|
||||
[folder-name handle]))
|
||||
|
||||
(defn backup-db-graph
|
||||
[repo _backup-type]
|
||||
(when (and repo (= repo (state/get-current-repo)))
|
||||
(when-let [backup-folder (ldb/get-key-value (db/get-db repo) :logseq.kv/graph-backup-folder)]
|
||||
(p/let [handle (idb/get-item (str "handle/" (js/btoa repo) "/" backup-folder))
|
||||
;; ensure file handle exists
|
||||
;; ask user to choose a folder again when access expires
|
||||
(p/let [handle (try
|
||||
(idb/get-item (str "handle/" (js/btoa repo) "/" backup-folder))
|
||||
(catch :default _e
|
||||
(throw (ex-info "Backup file handle no longer exists" {:repo repo}))))
|
||||
[_folder handle] (try
|
||||
(utils/verifyPermission handle true)
|
||||
[backup-folder handle]
|
||||
(catch :default e
|
||||
(js/console.error e)
|
||||
(choose-backup-folder repo)))
|
||||
repo-name (common-sqlite/sanitize-db-name repo)]
|
||||
(if handle
|
||||
(->
|
||||
@@ -297,9 +319,9 @@
|
||||
(when (and (config/db-based-graph? repo) util/web-platform? (utils/nfsSupported))
|
||||
(cancel-db-backup!)
|
||||
|
||||
(when backup-now? (backup-db-graph repo))
|
||||
(when backup-now? (backup-db-graph repo :backup-now))
|
||||
|
||||
;; run backup every hour
|
||||
(let [interval (js/setInterval #(backup-db-graph repo)
|
||||
(let [interval (js/setInterval #(backup-db-graph repo :auto)
|
||||
(* 1 60 60 1000))]
|
||||
(reset! *backup-interval interval)))))
|
||||
|
||||
@@ -210,3 +210,7 @@
|
||||
{:content (str "The graph '" graph "' already exists. Please try again with another name.")
|
||||
:status :error}])
|
||||
(create-db full-graph-name opts)))))
|
||||
|
||||
(defn fix-broken-graph!
|
||||
[graph]
|
||||
(state/<invoke-db-worker :thread-api/fix-broken-graph graph))
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
(let [page (db/get-page page-name)
|
||||
whiteboard? (db/whiteboard-page? page)]
|
||||
(if (and (not config/dev?)
|
||||
(or (ldb/hidden? page)
|
||||
(or (and (ldb/hidden? page) (not (ldb/property? page)))
|
||||
(and (ldb/built-in? page) (ldb/private-built-in-page? page))))
|
||||
(notification/show! "Cannot go to an internal page." :warning)
|
||||
(if-let [source (and (not ignore-alias?) (db/get-alias-source-page (state/get-current-repo) (:db/id page)))]
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
[frontend.handler.paste :as paste-handler]
|
||||
[frontend.handler.plugin :as plugin-handler]
|
||||
[frontend.handler.plugin-config :as plugin-config-handler]
|
||||
[frontend.handler.repo :as repo-handler]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.handler.search :as search-handler]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
@@ -592,6 +593,11 @@
|
||||
:inactive (not (util/electron?))
|
||||
:fn commit/show-commit-modal!}
|
||||
|
||||
:dev/fix-broken-graph {:binding []
|
||||
:inactive (not (state/developer-mode?))
|
||||
:db-graph? true
|
||||
:fn #(repo-handler/fix-broken-graph! (state/get-current-repo))}
|
||||
|
||||
:dev/replace-graph-with-db-file {:binding []
|
||||
:inactive (or (not (util/electron?)) (not (state/developer-mode?)))
|
||||
:fn :frontend.handler.common.developer/replace-graph-with-db-file}
|
||||
@@ -859,6 +865,7 @@
|
||||
:dev/show-page-ast
|
||||
:dev/replace-graph-with-db-file
|
||||
:dev/validate-db
|
||||
:dev/fix-broken-graph
|
||||
:ui/customize-appearance])
|
||||
(with-meta {:before m/enable-when-not-editing-mode!}))
|
||||
|
||||
@@ -1051,6 +1058,7 @@
|
||||
:dev/show-page-ast
|
||||
:dev/replace-graph-with-db-file
|
||||
:dev/validate-db
|
||||
:dev/fix-broken-graph
|
||||
:ui/clear-all-notifications]
|
||||
|
||||
:shortcut.category/plugins
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
result (state/<invoke-db-worker :thread-api/search-build-blocks-indice repo)
|
||||
blocks (if file-based?
|
||||
(->> result
|
||||
;; remove built-in properties from content
|
||||
;; remove built-in properties from content
|
||||
(map
|
||||
#(update % :content
|
||||
(fn [content]
|
||||
|
||||
@@ -1877,7 +1877,7 @@ Similar to re-frame subscriptions"
|
||||
(if (and page
|
||||
;; TODO: Use config/dev? when it's not a circular dep
|
||||
(not goog.DEBUG)
|
||||
(or (ldb/hidden? page)
|
||||
(or (and (ldb/hidden? page) (not (ldb/property? 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
|
||||
|
||||
@@ -275,6 +275,17 @@ html.is-mobile {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ui__icon svg {
|
||||
filter: brightness(0.8);
|
||||
transition: filter .15s;
|
||||
will-change: filter;
|
||||
}
|
||||
|
||||
.ui__icon:hover svg {
|
||||
filter: brightness(1);
|
||||
transition-duration: .15s;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
@apply text-base text-center flex items-center justify-center rounded border mr-2 relative;
|
||||
|
||||
|
||||
@@ -790,6 +790,11 @@
|
||||
(->> blocks
|
||||
(remove (fn [b] (= "true" (d/attr b "data-embed")))))))
|
||||
|
||||
#?(:cljs
|
||||
(defn remove-property-value-blocks [blocks]
|
||||
(->> blocks
|
||||
(remove (fn [b] (d/has-class? b "property-value-container"))))))
|
||||
|
||||
#?(:cljs
|
||||
(defn get-selected-text
|
||||
[]
|
||||
@@ -898,7 +903,8 @@
|
||||
(defn get-prev-block-non-collapsed-non-embed
|
||||
[block]
|
||||
(when-let [blocks (->> (get-blocks-noncollapse)
|
||||
remove-embedded-blocks)]
|
||||
remove-embedded-blocks
|
||||
remove-property-value-blocks)]
|
||||
(when-let [index (.indexOf blocks block)]
|
||||
(let [idx (dec index)]
|
||||
(when (>= idx 0)
|
||||
|
||||
@@ -906,6 +906,12 @@
|
||||
move-top-parents-to-library
|
||||
update-children-parent-and-order)))))
|
||||
|
||||
|
||||
(defn- empty-placeholder-add-block-uuid
|
||||
[_conn _search-db]
|
||||
[{:db/ident :logseq.property/empty-placeholder
|
||||
:block/uuid (common-uuid/gen-uuid :builtin-block-uuid :logseq.property/empty-placeholder)}])
|
||||
|
||||
(def ^:large-vars/cleanup-todo schema-version->updates
|
||||
"A vec of tuples defining datascript migrations. Each tuple consists of the
|
||||
schema version integer and a migration map. A migration map can have keys of :properties, :classes
|
||||
@@ -1005,8 +1011,8 @@
|
||||
[62 {:fix remove-block-schema}]
|
||||
[63 {:properties [:logseq.property.table/pinned-columns]}]
|
||||
[64 {:fix update-view-filter}]
|
||||
;;;; schema-version format: "<major>.<minor>"
|
||||
;;;; int number equals to "<major>" (without <minor>)
|
||||
;;;; schema-version format: "<major>.<minor>"
|
||||
;;;; int number equals to "<major>" (without <minor>)
|
||||
["64.1" {:properties [:logseq.property.view/group-by-property]
|
||||
:fix add-view-icons}]
|
||||
["64.2" {:properties [:logseq.property.view/feature-type]
|
||||
@@ -1018,7 +1024,8 @@
|
||||
["64.6" {:fix cardinality-one-multiple-values}]
|
||||
["64.7" {:fix rename-repeated-properties}]
|
||||
["64.8" {:fix rename-task-properties}]
|
||||
["64.9" {:fix fix-rename-parent-to-extends}]])
|
||||
["64.9" {:fix empty-placeholder-add-block-uuid}]
|
||||
["64.10" {:fix fix-rename-parent-to-extends}]])
|
||||
|
||||
(let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
|
||||
schema-version->updates)))
|
||||
|
||||
@@ -100,39 +100,43 @@
|
||||
[^js pool data]
|
||||
(.importDb ^js pool repo-path data))
|
||||
|
||||
(comment
|
||||
(defn- get-all-datoms-from-sqlite-db
|
||||
[db]
|
||||
(some->> (.exec db #js {:sql "select * from kvs"
|
||||
:rowMode "array"})
|
||||
bean/->clj
|
||||
(mapcat
|
||||
(fn [[_addr content _addresses]]
|
||||
(let [content' (sqlite-util/transit-read content)
|
||||
datoms (when (map? content')
|
||||
(:keys content'))]
|
||||
datoms)))
|
||||
distinct
|
||||
(map (fn [[e a v t]]
|
||||
(d/datom e a v t)))))
|
||||
(defn- get-all-datoms-from-sqlite-db
|
||||
[db]
|
||||
(some->> (.exec db #js {:sql "select * from kvs"
|
||||
:rowMode "array"})
|
||||
bean/->clj
|
||||
(mapcat
|
||||
(fn [[_addr content _addresses]]
|
||||
(let [content' (sqlite-util/transit-read content)
|
||||
datoms (when (map? content')
|
||||
(:keys content'))]
|
||||
datoms)))
|
||||
distinct
|
||||
(map (fn [[e a v t]]
|
||||
(d/datom e a v t)))))
|
||||
|
||||
(defn- rebuild-db-from-datoms!
|
||||
"Persistent-sorted-set has been broken, used addresses can't be found"
|
||||
[datascript-conn sqlite-db import-type]
|
||||
(let [datoms (get-all-datoms-from-sqlite-db sqlite-db)
|
||||
db (d/init-db [] db-schema/schema
|
||||
{:storage (storage/storage @datascript-conn)})
|
||||
db (d/db-with db
|
||||
(map (fn [d]
|
||||
[:db/add (:e d) (:a d) (:v d) (:t d)]) datoms))]
|
||||
(prn :debug :rebuild-db-from-datoms :datoms-count (count datoms))
|
||||
;; export db first
|
||||
(when-not import-type
|
||||
(worker-util/post-message :notification ["The SQLite db will be exported to avoid any data-loss." :warning false])
|
||||
(worker-util/post-message :export-current-db []))
|
||||
(.exec sqlite-db #js {:sql "delete from kvs"})
|
||||
(d/reset-conn! datascript-conn db)
|
||||
(db-migrate/fix-db! datascript-conn))))
|
||||
(defn- rebuild-db-from-datoms!
|
||||
"Persistent-sorted-set has been broken, used addresses can't be found"
|
||||
[datascript-conn sqlite-db]
|
||||
(let [datoms (get-all-datoms-from-sqlite-db sqlite-db)
|
||||
db (d/init-db [] db-schema/schema
|
||||
{:storage (storage/storage @datascript-conn)})
|
||||
db (d/db-with db
|
||||
(map (fn [d]
|
||||
[:db/add (:e d) (:a d) (:v d) (:t d)]) datoms))]
|
||||
(prn :debug :rebuild-db-from-datoms :datoms-count (count datoms))
|
||||
(worker-util/post-message :notification ["The SQLite db will be exported to avoid any data-loss." :warning false])
|
||||
(worker-util/post-message :export-current-db [])
|
||||
(.exec sqlite-db #js {:sql "delete from kvs"})
|
||||
(d/reset-conn! datascript-conn db)
|
||||
(db-migrate/fix-db! datascript-conn)))
|
||||
|
||||
(defn- fix-broken-graph
|
||||
[graph]
|
||||
(let [conn (worker-state/get-datascript-conn graph)
|
||||
sqlite-db (worker-state/get-sqlite-conn graph)]
|
||||
(when (and conn sqlite-db)
|
||||
(rebuild-db-from-datoms! conn sqlite-db))))
|
||||
|
||||
(comment
|
||||
(defn- gc-kvs-table!
|
||||
@@ -180,9 +184,25 @@
|
||||
(when (and compare-result (not (neg? compare-result))) ; >= 64.8
|
||||
(worker-util/post-message :capture-error
|
||||
{:error "db-missing-addresses-v2"
|
||||
:payload {:missing-addresses missing-addresses}}))))
|
||||
:payload {:missing-addresses (str missing-addresses)
|
||||
:db-schema-version (str version-in-db)}}))))
|
||||
missing-addresses))
|
||||
|
||||
(def get-to-delete-unused-addresses-sql
|
||||
"WITH to_delete(addr) AS (
|
||||
SELECT value
|
||||
FROM json_each(?)
|
||||
),
|
||||
referenced(addr) AS (
|
||||
SELECT json_each.value
|
||||
FROM kvs
|
||||
JOIN json_each(kvs.addresses)
|
||||
WHERE kvs.addr NOT IN (SELECT addr FROM to_delete)
|
||||
AND json_each.value IN (SELECT addr FROM to_delete)
|
||||
)
|
||||
SELECT addr FROM to_delete
|
||||
WHERE addr NOT IN (SELECT addr FROM referenced)")
|
||||
|
||||
(defn upsert-addr-content!
|
||||
"Upsert addr+data-seq. Update sqlite-cli/upsert-addr-content! when making changes"
|
||||
[db data delete-addrs*]
|
||||
@@ -193,19 +213,19 @@
|
||||
(.exec tx #js {:sql "INSERT INTO kvs (addr, content, addresses) values ($addr, $content, $addresses) on conflict(addr) do update set content = $content, addresses = $addresses"
|
||||
:bind item}))))
|
||||
(when (seq delete-addrs)
|
||||
(.transaction db (fn [tx]
|
||||
(doseq [addr delete-addrs]
|
||||
(.exec tx #js {:sql "Delete from kvs WHERE addr = ? AND NOT EXISTS (SELECT 1 FROM json_each(addresses) WHERE value = ?);"
|
||||
:bind #js [addr]}))))
|
||||
(let [result (.exec db #js {:sql get-to-delete-unused-addresses-sql
|
||||
:bind (js/JSON.stringify (clj->js delete-addrs))
|
||||
:rowMode "array"})
|
||||
non-refed-addrs (map #(aget % 0) result)]
|
||||
(when (seq non-refed-addrs)
|
||||
(.transaction db (fn [tx]
|
||||
(doseq [addr non-refed-addrs]
|
||||
(.exec tx #js {:sql "Delete from kvs where addr = ?"
|
||||
:bind #js [addr]}))))))
|
||||
(let [missing-addrs (when worker-util/dev?
|
||||
(seq (find-missing-addresses nil db {:delete-addrs delete-addrs})))]
|
||||
(if (seq missing-addrs)
|
||||
(worker-util/post-message :notification [(str "Bug!! Missing addresses: " missing-addrs) :error false])
|
||||
(when (seq delete-addrs)
|
||||
(.transaction db (fn [tx]
|
||||
(doseq [addr delete-addrs]
|
||||
(.exec tx #js {:sql "Delete from kvs WHERE addr = ? AND NOT EXISTS (SELECT 1 FROM json_each(addresses) WHERE value = ?);"
|
||||
:bind #js [addr]}))))))))))
|
||||
(when (seq missing-addrs)
|
||||
(worker-util/post-message :notification [(str "Bug!! Missing addresses: " missing-addrs) :error false]))))))
|
||||
|
||||
(defn restore-data-from-addr
|
||||
"Update sqlite-cli/restore-data-from-addr when making changes"
|
||||
@@ -771,6 +791,10 @@
|
||||
[repo]
|
||||
(get-all-page-titles-with-cache repo))
|
||||
|
||||
(def-thread-api :thread-api/fix-broken-graph
|
||||
[graph]
|
||||
(fix-broken-graph graph))
|
||||
|
||||
(comment
|
||||
(def-thread-api :general/dangerousRemoveAllDbs
|
||||
[]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[logseq.common.util :as common-util]
|
||||
[logseq.common.util.namespace :as ns-util]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.content :as db-content]
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[logseq.graph-parser.text :as text]))
|
||||
|
||||
@@ -193,7 +194,8 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
(defn- page-or-object?
|
||||
[entity]
|
||||
(and (or (ldb/page? entity) (ldb/object? entity))
|
||||
(not (ldb/hidden? entity))))
|
||||
(not (ldb/hidden? entity))
|
||||
(not (ldb/hidden? (:block/page entity)))))
|
||||
|
||||
(defn get-all-fuzzy-supported-blocks
|
||||
"Only pages and objects are supported now."
|
||||
@@ -205,7 +207,9 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
(map :e)))
|
||||
blocks (->> (distinct (concat page-ids object-ids))
|
||||
(map #(d/entity db %)))]
|
||||
(remove ldb/hidden? blocks)))
|
||||
(->> blocks
|
||||
(remove ldb/hidden?)
|
||||
(remove #(ldb/hidden? (:block/page %))))))
|
||||
|
||||
(defn- sanitize
|
||||
[content]
|
||||
@@ -219,13 +223,9 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
(ldb/closed-value? block)
|
||||
(and (string? title) (> (count title) 10000))
|
||||
(string/blank? title)) ; empty page or block
|
||||
;; Should properties be included in the search indice?
|
||||
;; It could slow down the search indexing, also it can be confusing
|
||||
;; if the showing properties are not useful to users.
|
||||
;; (let [content (if (and db-based? (seq (:block/properties block)))
|
||||
;; (str content (when (not= content "") "\n") (get-db-properties-str db properties))
|
||||
;; content)])
|
||||
(let [title (ldb/get-title-with-parents (assoc block :block.temp/search? true))]
|
||||
(let [title (-> block
|
||||
(update :block/title ldb/get-title-with-parents)
|
||||
db-content/recur-replace-uuid-in-block-title)]
|
||||
(when uuid
|
||||
{:id (str uuid)
|
||||
:page (str (or (:block/uuid page) uuid))
|
||||
@@ -370,11 +370,11 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
set)
|
||||
blocks-to-add-set)]
|
||||
{:blocks-to-remove (->>
|
||||
(keep #(d/entity db-before %) blocks-to-remove-set)
|
||||
(remove ldb/hidden?))
|
||||
(keep #(d/entity db-before %) blocks-to-remove-set))
|
||||
:blocks-to-add (->>
|
||||
(keep #(d/entity db-after %) blocks-to-add-set')
|
||||
(remove ldb/hidden?))})))
|
||||
(remove ldb/hidden?)
|
||||
(remove #(ldb/hidden? (:block/page %))))})))
|
||||
|
||||
(defn- get-affected-blocks
|
||||
[repo tx-report]
|
||||
|
||||
@@ -786,4 +786,5 @@
|
||||
:dev/show-page-ast "(Dev) Show page AST"
|
||||
:dev/replace-graph-with-db-file "(Dev) Replace graph with its db.sqlite file"
|
||||
:dev/validate-db "(Dev) Validate current graph"
|
||||
:dev/fix-broken-graph "(Dev) Fix current broken graph"
|
||||
:window/close "Close window"}}
|
||||
|
||||
Reference in New Issue
Block a user