From ddf977bf52507902e23f788b5f5d4f3a6bb13cf4 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 16:35:01 +0800 Subject: [PATCH 01/48] enhance(rtc): show upload logs when init uploading graph --- src/main/frontend/components/header.cljs | 2 + .../frontend/components/rtc/indicator.cljs | 99 ++++++++++--------- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/main/frontend/components/header.cljs b/src/main/frontend/components/header.cljs index df22388eb9..e7292861ba 100644 --- a/src/main/frontend/components/header.cljs +++ b/src/main/frontend/components/header.cljs @@ -387,6 +387,8 @@ (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)) diff --git a/src/main/frontend/components/rtc/indicator.cljs b/src/main/frontend/components/rtc/indicator.cljs index a849a867ca..b0e625de32 100644 --- a/src/main/frontend/components/rtc/indicator.cljs +++ b/src/main/frontend/components/rtc/indicator.cljs @@ -138,19 +138,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 +169,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 +198,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 +223,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..."))) From f5715abfa5199d17b1be32835adf61939b9db110 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 16:36:43 +0800 Subject: [PATCH 02/48] fix lint --- src/main/frontend/components/rtc/indicator.cljs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/frontend/components/rtc/indicator.cljs b/src/main/frontend/components/rtc/indicator.cljs index b0e625de32..e39786acc5 100644 --- a/src/main/frontend/components/rtc/indicator.cljs +++ b/src/main/frontend/components/rtc/indicator.cljs @@ -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] From 6602b814ae4c5b14b1106747e22eabf670ad7cc0 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 18 May 2025 16:36:47 +0800 Subject: [PATCH 03/48] feat: add command fix broken graph --- src/main/frontend/handler/repo.cljs | 8 ++- .../frontend/modules/shortcut/config.cljs | 7 ++ src/main/frontend/worker/db_worker.cljs | 72 ++++++++++--------- src/resources/dicts/en.edn | 1 + 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/main/frontend/handler/repo.cljs b/src/main/frontend/handler/repo.cljs index dfd7992cbb..90b2a50384 100644 --- a/src/main/frontend/handler/repo.cljs +++ b/src/main/frontend/handler/repo.cljs @@ -25,8 +25,8 @@ [frontend.util :as util] [frontend.util.fs :as util-fs] [frontend.util.text :as text-util] - [promesa.core :as p] - [logseq.common.config :as common-config])) + [logseq.common.config :as common-config] + [promesa.core :as p])) ;; Project settings should be checked in two situations: ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file) @@ -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/> (.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! @@ -771,6 +775,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 [] diff --git a/src/resources/dicts/en.edn b/src/resources/dicts/en.edn index de02d4b377..25b5e5f18d 100644 --- a/src/resources/dicts/en.edn +++ b/src/resources/dicts/en.edn @@ -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"}} From 9b5d55d00593393e63640be9bd4e12d13426818c Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 18 May 2025 16:45:45 +0800 Subject: [PATCH 04/48] fix: send current db schema-version to sentry when missing addrs --- src/main/frontend/handler/events.cljs | 17 +++++++++-------- src/main/frontend/worker/db_worker.cljs | 3 ++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index dea7c8bea4..816b32f645 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -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})))) diff --git a/src/main/frontend/worker/db_worker.cljs b/src/main/frontend/worker/db_worker.cljs index c0de9e9ecb..bf65108030 100644 --- a/src/main/frontend/worker/db_worker.cljs +++ b/src/main/frontend/worker/db_worker.cljs @@ -184,7 +184,8 @@ (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)) (defn upsert-addr-content! From 35fc1200561781941ee58301fd7bfd1872ac1765 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 17:41:01 +0800 Subject: [PATCH 05/48] test(e2e): wait before fill --- clj-e2e/src/logseq/e2e/block.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/clj-e2e/src/logseq/e2e/block.clj b/clj-e2e/src/logseq/e2e/block.clj index fb9e819549..f071b6a8a1 100644 --- a/clj-e2e/src/logseq/e2e/block.clj +++ b/clj-e2e/src/logseq/e2e/block.clj @@ -15,6 +15,7 @@ (defn save-block [text] + (util/wait-timeout 10) (w/fill util/editor-q text) (assert/assert-is-visible (loc/filter util/editor-q :has-text text))) From b5a73b9b72088a3068722ae4a6f11f4f3955f80b Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 17:55:19 +0800 Subject: [PATCH 06/48] test(e2e): wait before fill (2) --- clj-e2e/src/logseq/e2e/block.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clj-e2e/src/logseq/e2e/block.clj b/clj-e2e/src/logseq/e2e/block.clj index f071b6a8a1..d5a7a80a57 100644 --- a/clj-e2e/src/logseq/e2e/block.clj +++ b/clj-e2e/src/logseq/e2e/block.clj @@ -15,7 +15,7 @@ (defn save-block [text] - (util/wait-timeout 10) + (util/wait-timeout 100) (w/fill util/editor-q text) (assert/assert-is-visible (loc/filter util/editor-q :has-text text))) From 1ac6ff9121d9b57bfad726310bcbdcce3b406e72 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 18 May 2025 18:18:00 +0800 Subject: [PATCH 07/48] fix: ensure editor is table before fill https://playwright.dev/java/docs/actionability#stable --- clj-e2e/src/logseq/e2e/block.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clj-e2e/src/logseq/e2e/block.clj b/clj-e2e/src/logseq/e2e/block.clj index d5a7a80a57..1dcc5e4030 100644 --- a/clj-e2e/src/logseq/e2e/block.clj +++ b/clj-e2e/src/logseq/e2e/block.clj @@ -15,7 +15,7 @@ (defn save-block [text] - (util/wait-timeout 100) + (w/click util/editor-q) (w/fill util/editor-q text) (assert/assert-is-visible (loc/filter util/editor-q :has-text text))) From 3491381877eba60dc0a9599653c90cb6eae40fa6 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 23:21:59 +0800 Subject: [PATCH 08/48] test(e2e): divide test-ns into '-basic-test' and '-extra-test' --- clj-e2e/bb.edn | 8 ++-- clj-e2e/dev/user.clj | 42 +++++++++---------- ...mands_test.clj => commands_basic_test.clj} | 2 +- ...abs_test.clj => multi_tabs_basic_test.clj} | 2 +- ...liner_test.clj => outliner_basic_test.clj} | 2 +- ...lugins_test.clj => plugins_basic_test.clj} | 2 +- ...ence_test.clj => reference_basic_test.clj} | 2 +- clj-e2e/test/logseq/e2e/rtc_extra_test.clj | 8 ++++ 8 files changed, 39 insertions(+), 29 deletions(-) rename clj-e2e/test/logseq/e2e/{commands_test.clj => commands_basic_test.clj} (99%) rename clj-e2e/test/logseq/e2e/{multi_tabs_test.clj => multi_tabs_basic_test.clj} (98%) rename clj-e2e/test/logseq/e2e/{outliner_test.clj => outliner_basic_test.clj} (98%) rename clj-e2e/test/logseq/e2e/{plugins_test.clj => plugins_basic_test.clj} (97%) rename clj-e2e/test/logseq/e2e/{reference_test.clj => reference_basic_test.clj} (98%) create mode 100644 clj-e2e/test/logseq/e2e/rtc_extra_test.clj diff --git a/clj-e2e/bb.edn b/clj-e2e/bb.edn index 6bc9419ff3..45d13191be 100644 --- a/clj-e2e/bb.edn +++ b/clj-e2e/bb.edn @@ -12,9 +12,11 @@ prn {:task (clojure "-X clojure.core/prn" cli-opts)} - test {:task (do - (clojure "-T:build test") - (System/exit 0))} + test {:doc "run tests (ns'es ending in '-basic-test')" + :task (clojure "-M:test -r \".*\\-basic\\-test$\"")} + + extra-test {:doc "run tests (ns'es ending in '-extra-test')" + :task (clojure "-M:test -r \".*\\-extra\\-test$\"")} -dev {:depends [serve prn test]} diff --git a/clj-e2e/dev/user.clj b/clj-e2e/dev/user.clj index b2b8273cc8..6190fc7d52 100644 --- a/clj-e2e/dev/user.clj +++ b/clj-e2e/dev/user.clj @@ -2,15 +2,15 @@ "fns used on repl" (:require [clojure.test :refer [run-tests run-test]] [logseq.e2e.block :as b] - [logseq.e2e.commands-test] + [logseq.e2e.commands-basic-test] [logseq.e2e.config :as config] [logseq.e2e.fixtures :as fixtures] [logseq.e2e.graph :as graph] [logseq.e2e.keyboard :as k] - [logseq.e2e.multi-tabs-test] - [logseq.e2e.outliner-test] - [logseq.e2e.plugins-test] - [logseq.e2e.reference-test] + [logseq.e2e.multi-tabs-basic-test] + [logseq.e2e.outliner-basic-test] + [logseq.e2e.plugins-basic-test] + [logseq.e2e.reference-basic-test] [logseq.e2e.rtc-basic-test] [logseq.e2e.util :as util] [wally.main :as w] @@ -31,12 +31,12 @@ (defn run-commands-test [] - (->> (future (run-tests 'logseq.e2e.commands-test)) + (->> (future (run-tests 'logseq.e2e.commands-basic-test)) (swap! *futures assoc :commands-test))) (defn run-outliner-test [] - (->> (future (run-tests 'logseq.e2e.outliner-test)) + (->> (future (run-tests 'logseq.e2e.outliner-basic-test)) (swap! *futures assoc :outliner-test))) (defn run-rtc-basic-test @@ -46,27 +46,27 @@ (defn run-multi-tabs-test [] - (->> (future (run-tests 'logseq.e2e.multi-tabs-test)) + (->> (future (run-tests 'logseq.e2e.multi-tabs-basic-test)) (swap! *futures assoc :multi-tabs-test))) (defn run-reference-test [] - (->> (future (run-tests 'logseq.e2e.reference-test)) + (->> (future (run-tests 'logseq.e2e.reference-basic-test)) (swap! *futures assoc :reference-test))) (defn run-plugins-test [] - (->> (future (run-tests 'logseq.e2e.plugins-test)) + (->> (future (run-tests 'logseq.e2e.plugins-basic-test)) (swap! *futures assoc :plugins-test))) -(defn run-all-test +(defn run-all-basic-test [] - (run-tests 'logseq.e2e.commands-test - 'logseq.e2e.multi-tabs-test - 'logseq.e2e.outliner-test + (run-tests 'logseq.e2e.commands-basic-test + 'logseq.e2e.multi-tabs-basic-test + 'logseq.e2e.outliner-basic-test 'logseq.e2e.rtc-basic-test - 'logseq.e2e.plugins-test - 'logseq.e2e.reference-test)) + 'logseq.e2e.plugins-basic-test + 'logseq.e2e.reference-basic-test)) (defn start [] @@ -92,17 +92,17 @@ (w/wait-for (first (util/get-edit-block-container)) {:state :detached})) - (run-tests 'logseq.e2e.commands-test - 'logseq.e2e.multi-tabs-test - 'logseq.e2e.outliner-test + (run-tests 'logseq.e2e.commands-basic-test + 'logseq.e2e.multi-tabs-basic-test + 'logseq.e2e.outliner-basic-test 'logseq.e2e.rtc-basic-test) (do (reset! config/*headless true) (reset! config/*slow-mo 10) - (run-tests 'logseq.e2e.reference-test) + (run-tests 'logseq.e2e.reference-basic-test) (dotimes [i 10] - (run-tests 'logseq.e2e.reference-test))) + (run-tests 'logseq.e2e.reference-basic-test))) ;; ) diff --git a/clj-e2e/test/logseq/e2e/commands_test.clj b/clj-e2e/test/logseq/e2e/commands_basic_test.clj similarity index 99% rename from clj-e2e/test/logseq/e2e/commands_test.clj rename to clj-e2e/test/logseq/e2e/commands_basic_test.clj index 9153e01bf6..16d789dbc5 100644 --- a/clj-e2e/test/logseq/e2e/commands_test.clj +++ b/clj-e2e/test/logseq/e2e/commands_basic_test.clj @@ -1,4 +1,4 @@ -(ns logseq.e2e.commands-test +(ns logseq.e2e.commands-basic-test (:require [clj-time.core :as t] [clj-time.local :as tl] diff --git a/clj-e2e/test/logseq/e2e/multi_tabs_test.clj b/clj-e2e/test/logseq/e2e/multi_tabs_basic_test.clj similarity index 98% rename from clj-e2e/test/logseq/e2e/multi_tabs_test.clj rename to clj-e2e/test/logseq/e2e/multi_tabs_basic_test.clj index 9f39a8e54a..471690e6bb 100644 --- a/clj-e2e/test/logseq/e2e/multi_tabs_test.clj +++ b/clj-e2e/test/logseq/e2e/multi_tabs_basic_test.clj @@ -1,4 +1,4 @@ -(ns logseq.e2e.multi-tabs-test +(ns logseq.e2e.multi-tabs-basic-test (:require [clojure.test :refer [deftest is testing use-fixtures]] [logseq.e2e.assert :as assert] [logseq.e2e.block :as b] diff --git a/clj-e2e/test/logseq/e2e/outliner_test.clj b/clj-e2e/test/logseq/e2e/outliner_basic_test.clj similarity index 98% rename from clj-e2e/test/logseq/e2e/outliner_test.clj rename to clj-e2e/test/logseq/e2e/outliner_basic_test.clj index 5009cfb90a..791d308cec 100644 --- a/clj-e2e/test/logseq/e2e/outliner_test.clj +++ b/clj-e2e/test/logseq/e2e/outliner_basic_test.clj @@ -1,4 +1,4 @@ -(ns logseq.e2e.outliner-test +(ns logseq.e2e.outliner-basic-test (:require [clojure.test :refer [deftest testing is use-fixtures]] [logseq.e2e.block :as b] diff --git a/clj-e2e/test/logseq/e2e/plugins_test.clj b/clj-e2e/test/logseq/e2e/plugins_basic_test.clj similarity index 97% rename from clj-e2e/test/logseq/e2e/plugins_test.clj rename to clj-e2e/test/logseq/e2e/plugins_basic_test.clj index cea2782168..af219db19f 100644 --- a/clj-e2e/test/logseq/e2e/plugins_test.clj +++ b/clj-e2e/test/logseq/e2e/plugins_basic_test.clj @@ -1,4 +1,4 @@ -(ns logseq.e2e.plugins-test +(ns logseq.e2e.plugins-basic-test (:require [clojure.string :as string] [clojure.test :refer [deftest testing is use-fixtures]] diff --git a/clj-e2e/test/logseq/e2e/reference_test.clj b/clj-e2e/test/logseq/e2e/reference_basic_test.clj similarity index 98% rename from clj-e2e/test/logseq/e2e/reference_test.clj rename to clj-e2e/test/logseq/e2e/reference_basic_test.clj index 9bd3a051d7..2300dcbc56 100644 --- a/clj-e2e/test/logseq/e2e/reference_test.clj +++ b/clj-e2e/test/logseq/e2e/reference_basic_test.clj @@ -1,4 +1,4 @@ -(ns logseq.e2e.reference-test +(ns logseq.e2e.reference-basic-test (:require [clojure.test :refer [deftest testing is use-fixtures]] [logseq.e2e.assert :as assert] diff --git a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj new file mode 100644 index 0000000000..a600e6619a --- /dev/null +++ b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj @@ -0,0 +1,8 @@ +(ns logseq.e2e.rtc-extra-test + (:require + [clojure.test :refer [deftest testing is use-fixtures]])) + + +(deftest name-test + (testing "Context of the test assertions" + (is true))) From c7271304e19e425790fc0c865bad499a31b8bfc9 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Sun, 18 May 2025 23:47:33 +0800 Subject: [PATCH 09/48] test(e2e): add exit-0 back --- clj-e2e/bb.edn | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clj-e2e/bb.edn b/clj-e2e/bb.edn index 45d13191be..c2e4c782b4 100644 --- a/clj-e2e/bb.edn +++ b/clj-e2e/bb.edn @@ -13,10 +13,12 @@ prn {:task (clojure "-X clojure.core/prn" cli-opts)} test {:doc "run tests (ns'es ending in '-basic-test')" - :task (clojure "-M:test -r \".*\\-basic\\-test$\"")} + :task (do (clojure "-M:test -r \".*\\-basic\\-test$\"") + (System/exit 0))} extra-test {:doc "run tests (ns'es ending in '-extra-test')" - :task (clojure "-M:test -r \".*\\-extra\\-test$\"")} + :task (do (clojure "-M:test -r \".*\\-extra\\-test$\"") + (System/exit 0))} -dev {:depends [serve prn test]} From 28d42907c9387cf6d82fab232727142c51cd10b8 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 15:14:18 +0800 Subject: [PATCH 10/48] fix: re-ask permission for backup filehandle when expired fix https://github.com/logseq/db-test/issues/276 --- src/main/frontend/components/export.cljs | 95 ++++++++++++------------ src/main/frontend/handler/export.cljs | 30 +++++++- 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/src/main/frontend/components/export.cljs b/src/main/frontend/components/export.cljs index b439005cd9..f3901dd346 100644 --- a/src/main/frontend/components/export.cljs +++ b/src/main/frontend/components/export.cljs @@ -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)])]]))) diff --git a/src/main/frontend/handler/export.cljs b/src/main/frontend/handler/export.cljs index e79c926f7e..529a8deef9 100644 --- a/src/main/frontend/handler/export.cljs +++ b/src/main/frontend/handler/export.cljs @@ -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 :defult _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))))) From 8b1984e408e452d1b474c725a534f0a0b2b4459b Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 15:35:52 +0800 Subject: [PATCH 11/48] fix: wrong breadcrumb when selecting nodes --- src/main/frontend/components/property/value.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 97d9baf0df..67808e0725 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -756,7 +756,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)) From 26b8ce2370aa5832c836152f88088383d10402b0 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 16:03:17 +0800 Subject: [PATCH 12/48] enhance(ux): display blocks refs as page refs for db graphs --- src/main/frontend/components/block.cljs | 117 ++++++++---------- src/main/frontend/components/class.cljs | 2 +- .../components/file_based/hierarchy.cljs | 5 +- .../frontend/components/right_sidebar.cljs | 9 +- 4 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 44329b9f09..477bb0addb 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -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} @@ -705,12 +705,14 @@ (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)) (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 @@ -730,7 +732,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) @@ -945,26 +947,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) @@ -1070,7 +1068,7 @@ (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*) @@ -1084,17 +1082,20 @@ :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?)] + (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)) + (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 [:span.page-reference {:data-ref (str uuid-or-title)} (when brackets? @@ -1111,17 +1112,7 @@ {: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))] - - :else - (page-cp config' (if (uuid? uuid-or-title) - {:block/uuid uuid-or-title} - {:block/name uuid-or-title}))))))) + [:span.text-gray-500.bracket page-ref/right-brackets])]))))) (defn- latex-environment-content [name option content] @@ -1329,27 +1320,29 @@ (rum/defc block-reference [config id label] - (let [block-id (and id (if (uuid? id) id (parse-uuid id))) - [block set-block!] (hooks/use-state (db/entity [:block/uuid block-id])) - self-reference? (when (set? (:ref-set config)) - (contains? (:ref-set config) block-id))] - (hooks/use-effect! - (fn [] - (p/let [block (db-async/elem :a {:href s @@ -1509,9 +1502,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] @@ -1535,7 +1528,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) @@ -1557,7 +1550,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") @@ -1979,7 +1972,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] diff --git a/src/main/frontend/components/class.cljs b/src/main/frontend/components/class.cljs index 3ceb6708c1..4489d19ea8 100644 --- a/src/main/frontend/components/class.cljs +++ b/src/main/frontend/components/class.cljs @@ -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/_parent child)) (ui/foldable title diff --git a/src/main/frontend/components/file_based/hierarchy.cljs b/src/main/frontend/components/file_based/hierarchy.cljs index 6a1f92f359..d3178bb603 100644 --- a/src/main/frontend/components/file_based/hierarchy.cljs +++ b/src/main/frontend/components/file_based/hierarchy.cljs @@ -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})]))) diff --git a/src/main/frontend/components/right_sidebar.cljs b/src/main/frontend/components/right_sidebar.cljs index 66986c4e3d..a898507adb 100644 --- a/src/main/frontend/components/right_sidebar.cljs +++ b/src/main/frontend/components/right_sidebar.cljs @@ -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 [] From 87d2a56b6358116528573640fa2bfade1845d788 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 16:21:11 +0800 Subject: [PATCH 13/48] fix: remove blocks of hidden pages from search --- src/main/frontend/worker/search.cljs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/worker/search.cljs b/src/main/frontend/worker/search.cljs index 3923badf5c..c14922b9a7 100644 --- a/src/main/frontend/worker/search.cljs +++ b/src/main/frontend/worker/search.cljs @@ -193,7 +193,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 +206,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] @@ -370,11 +373,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] From b473a20874fb7afe3905ed51777cb9b3d685151a Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 17:57:38 +0800 Subject: [PATCH 14/48] fix: can't remove hidden property pages --- deps/db/src/logseq/db/frontend/entity_util.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/db/src/logseq/db/frontend/entity_util.cljs b/deps/db/src/logseq/db/frontend/entity_util.cljs index f01ad9f464..2a92fb003d 100644 --- a/deps/db/src/logseq/db/frontend/entity_util.cljs +++ b/deps/db/src/logseq/db/frontend/entity_util.cljs @@ -65,7 +65,8 @@ (when page (if (string? page) (string/starts-with? page "$$$") - (when (or (map? page) (de/entity? page)) + (when (and (or (map? page) (de/entity? page)) + (not (property? page))) (:logseq.property/hide? page)))))) (defn object? From 60f2b3eea262a85f0375d6ffc8aad41776d0b191 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 18:26:10 +0800 Subject: [PATCH 15/48] fix: mod+enter can't open search in sidebar --- .../frontend/components/right_sidebar.cljs | 133 ++++++++++-------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/src/main/frontend/components/right_sidebar.cljs b/src/main/frontend/components/right_sidebar.cljs index a898507adb..50d9b95eb3 100644 --- a/src/main/frontend/components/right_sidebar.cljs +++ b/src/main/frontend/components/right_sidebar.cljs @@ -69,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- + (p/do! + (when-not (contains? #{:contents :search} block-type) + (db-async/ (when (zero? idx) (drop-indicator (dec idx) drag-to)) From 5b7fba1bcb35fb1c6c29fd1f77a34021ac37be0a Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 08:33:56 -0400 Subject: [PATCH 16/48] fix: catch typo --- src/main/frontend/handler/export.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/handler/export.cljs b/src/main/frontend/handler/export.cljs index 529a8deef9..43cf57e89e 100644 --- a/src/main/frontend/handler/export.cljs +++ b/src/main/frontend/handler/export.cljs @@ -269,7 +269,7 @@ ;; 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 :defult _e + (catch :default _e (throw (ex-info "Backup file handle no longer exists" {:repo repo})))) [_folder handle] (try (utils/verifyPermission handle true) From 19ad493852364b0147e48d12216a3e585169a283 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 08:55:39 -0400 Subject: [PATCH 17/48] fix: new dev cmd inconsistently appearing in cmd list Db only cmds should use :db-graph? not :inactive. Using :inactive doesn't work for specific graph types. For example if the app loads with a file graph, the dev cmd is marked as inactive and after switching to db graph it is still inactive --- src/main/frontend/modules/shortcut/config.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/modules/shortcut/config.cljs b/src/main/frontend/modules/shortcut/config.cljs index caadfd6642..f4c5b67716 100644 --- a/src/main/frontend/modules/shortcut/config.cljs +++ b/src/main/frontend/modules/shortcut/config.cljs @@ -594,7 +594,8 @@ :fn commit/show-commit-modal!} :dev/fix-broken-graph {:binding [] - :inactive (not (config/db-based-graph? (state/get-current-repo))) + :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 [] From 9ceefde5b776184f073ea3cab7958557c115a8b9 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 20:31:06 +0800 Subject: [PATCH 18/48] fix: show deep reference title instead of id when searching blocks --- deps/db/src/logseq/db/common/entity_plus.cljc | 38 +++++++------- deps/db/src/logseq/db/frontend/content.cljs | 50 ++++++++++++++----- src/main/frontend/common/file/core.cljs | 23 +-------- src/main/frontend/db/model.cljs | 2 +- src/main/frontend/search/browser.cljs | 2 +- src/main/frontend/worker/search.cljs | 11 ++-- 6 files changed, 63 insertions(+), 63 deletions(-) diff --git a/deps/db/src/logseq/db/common/entity_plus.cljc b/deps/db/src/logseq/db/common/entity_plus.cljc index a54e7265ea..06e4548363 100644 --- a/deps/db/src/logseq/db/common/entity_plus.cljc +++ b/deps/db/src/logseq/db/common/entity_plus.cljc @@ -21,7 +21,7 @@ ;; File graph only attributes. Can these be removed if this is only called in db graphs? :block/pre-block? :block/scheduled :block/deadline :block/type :block/name :block/marker - :block.temp/ast-title :block.temp/search? + :block.temp/ast-title :block.temp/fully-loaded? :block.temp/ast-body :db/valueType :db/cardinality :db/ident :db/index @@ -91,18 +91,16 @@ db-based? (db-based-graph? db)] (if (and db-based? (entity-util/journal? e)) (get-journal-title db e) - (let [search? (get (.-kv e) :block.temp/search?)] - (or - (when-not (and search? (keyword-identical? k :block/title)) - (get (.-kv e) k)) - (let [result (lookup-entity e k default-value) - ;; Replace title for pages only, otherwise it'll recursively - ;; replace block id refs if there're cycle references of blocks - refs (:block/refs e) - result' (if (and (string? result) refs) - (db-content/id-ref->title-ref result refs search?) - result)] - (or result' default-value))))))) + (or + (get (.-kv e) k) + (let [result (lookup-entity e k default-value) + ;; Replace title for pages only, otherwise it'll recursively + ;; replace block id refs if there're cycle references of blocks + refs (:block/refs e) + result' (if (and (string? result) refs) + (db-content/id-ref->title-ref result refs) + result)] + (or result' default-value)))))) (defn- lookup-kv-with-default-value [db ^Entity e k default-value] @@ -162,12 +160,12 @@ ;; cache :block/title :block/title - (or (when-not (get (.-kv e) :block.temp/search?) - (:block.temp/cached-title @(.-cache e))) - (let [title (get-block-title e k default-value)] - (vreset! (.-cache e) (assoc @(.-cache e) - :block.temp/cached-title title)) - title)) + (or + (:block.temp/cached-title @(.-cache e)) + (let [title (get-block-title e k default-value)] + (vreset! (.-cache e) (assoc @(.-cache e) + :block.temp/cached-title title)) + title)) :block/_parent (->> (lookup-entity e k default-value) @@ -191,7 +189,7 @@ (let [v @(.-cache this) v' (if (:block/title v) (assoc v :block/title - (db-content/id-ref->title-ref (:block/title v) (:block/refs this) (:block.temp/search? this))) + (db-content/id-ref->title-ref (:block/title v) (:block/refs this))) v)] (concat (seq v') (seq (.-kv this))))) diff --git a/deps/db/src/logseq/db/frontend/content.cljs b/deps/db/src/logseq/db/frontend/content.cljs index 0952461c18..5b7433b8e7 100644 --- a/deps/db/src/logseq/db/frontend/content.cljs +++ b/deps/db/src/logseq/db/frontend/content.cljs @@ -41,22 +41,25 @@ (defn id-ref->title-ref "Convert id ref backs to page name refs using refs." - [content* refs* search?] - (let [refs (filter common-entity-util/page? refs*) + [content* refs* & {:keys [replace-block-id?] + :or {replace-block-id? false}}] + (let [refs (if replace-block-id? + ;; The caller need to handle situations including + ;; mutual references and circle references. + refs* + (filter common-entity-util/page? refs*)) content (str content*)] (if (re-find id-ref-pattern content) (reduce (fn [content ref] (if (:block/title ref) - (if (or (entity-util/page? ref) search?) - (let [content' (if (not (string/includes? (:block/title ref) " ")) - (string/replace content - (str "#" (page-ref/->page-ref (:block/uuid ref))) - (str "#" (:block/title ref))) - content)] - (string/replace content' (page-ref/->page-ref (:block/uuid ref)) - (page-ref/->page-ref (:block/title ref)))) - content) + (let [content' (if (not (string/includes? (:block/title ref) " ")) + (string/replace content + (str "#" (page-ref/->page-ref (:block/uuid ref))) + (str "#" (:block/title ref))) + content)] + (string/replace content' (page-ref/->page-ref (:block/uuid ref)) + (page-ref/->page-ref (:block/title ref)))) content)) content (sort-refs refs)) @@ -125,7 +128,7 @@ [db item eid] (if-let [content (:block/title item)] (let [refs (:block/refs (d/entity db eid))] - (assoc item :block/title (id-ref->title-ref content refs false))) + (assoc item :block/title (id-ref->title-ref content refs))) item)) (defn replace-tags-with-id-refs @@ -164,3 +167,26 @@ content (sort-refs tags)) (string/trim))) + +(defn recur-replace-uuid-in-block-title + "Convert id ref (recursively) backs to page name refs, returns replaced title" + ([ent] + (recur-replace-uuid-in-block-title ent 10)) + ([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 (id-ref->title-ref (:block/title ent) ref-set {:replace-block-id? true}) + last-result nil + depth 0] + (if (or (>= depth max-depth) + (= last-result result)) + result + (recur (id-ref->title-ref result ref-set) result (inc depth))))))) diff --git a/src/main/frontend/common/file/core.cljs b/src/main/frontend/common/file/core.cljs index b352dc563b..26bcf2d18b 100644 --- a/src/main/frontend/common/file/core.cljs +++ b/src/main/frontend/common/file/core.cljs @@ -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))) diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index 887c34ac64..17761248d2 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -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)))) diff --git a/src/main/frontend/search/browser.cljs b/src/main/frontend/search/browser.cljs index b202498ff2..709f82f9d1 100644 --- a/src/main/frontend/search/browser.cljs +++ b/src/main/frontend/search/browser.cljs @@ -19,7 +19,7 @@ result (state/> result - ;; remove built-in properties from content + ;; remove built-in properties from content (map #(update % :content (fn [content] diff --git a/src/main/frontend/worker/search.cljs b/src/main/frontend/worker/search.cljs index c14922b9a7..51831fed16 100644 --- a/src/main/frontend/worker/search.cljs +++ b/src/main/frontend/worker/search.cljs @@ -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])) @@ -222,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)) From b8a831b38c34ea712c8ac41ad4a8b10baedc0776 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 21:50:24 +0800 Subject: [PATCH 19/48] fix: recursively replace ref ids with title for search/prop value --- deps/db/src/logseq/db/frontend/content.cljs | 7 ++++--- src/main/frontend/components/block.cljs | 4 +--- src/main/frontend/components/editor.cljs | 12 ++++++++---- src/main/frontend/components/property/value.cljs | 8 +++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/content.cljs b/deps/db/src/logseq/db/frontend/content.cljs index 5b7433b8e7..3adbdc0d4b 100644 --- a/deps/db/src/logseq/db/frontend/content.cljs +++ b/deps/db/src/logseq/db/frontend/content.cljs @@ -182,11 +182,12 @@ 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 (id-ref->title-ref (:block/title ent) ref-set {:replace-block-id? true}) + (recur (apply conj result-refs next-refs) next-refs (inc depth)))))) + opts {:replace-block-id? true}] + (loop [result (id-ref->title-ref (:block/title ent) ref-set opts) last-result nil depth 0] (if (or (>= depth max-depth) (= last-result result)) result - (recur (id-ref->title-ref result ref-set) result (inc depth))))))) + (recur (id-ref->title-ref result ref-set opts) result (inc depth))))))) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 477bb0addb..c08a767979 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -707,8 +707,7 @@ (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?)) @@ -3186,7 +3185,6 @@ parents (if more? (take-last level-limit parents) parents) config (assoc config :breadcrumb? true - :disable-redirect? true :disable-preview? true :stop-click-event? false)] (when show? diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 5f34ad8b92..2e6ef40a36 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -31,6 +31,7 @@ [logseq.common.util.page-ref :as page-ref] [logseq.db :as ldb] [logseq.db.frontend.class :as db-class] + [logseq.db.frontend.content :as db-content] [logseq.graph-parser.property :as gp-property] [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] @@ -183,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 (not (or db-tag? (:page? block) (ldb/page? block))) @@ -218,10 +221,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? diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 67808e0725..cd5f6c1043 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -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) @@ -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? From 929ae21d21c985eada7fabdcc102ca8dfd8e6cb4 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 10:00:33 -0400 Subject: [PATCH 20/48] enhance: only run export patch for initial version up to 64.8 One less postwalk for large graphs. Dunno how long this patch will be in. For https://github.com/logseq/db-test/issues/278 --- deps/db/src/logseq/db/sqlite/export.cljs | 29 ++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/deps/db/src/logseq/db/sqlite/export.cljs b/deps/db/src/logseq/db/sqlite/export.cljs index 00c21ef6ac..208a9f0560 100644 --- a/deps/db/src/logseq/db/sqlite/export.cljs +++ b/deps/db/src/logseq/db/sqlite/export.cljs @@ -814,18 +814,23 @@ (defn- patch-invalid-keywords "Fixes invalids keywords whose name start with a number e.g. :user.property/2ndsomething" [m] - (walk/postwalk - (fn [e] - (if (and (keyword? e) (some-> (namespace e) (string/starts-with? "user."))) - ;; Copied from create-db-ident-from-name since this may be shortlived - (let [sanitized-kw (keyword (namespace e) - (->> (string/replace-first (name e) #"^(\d)" "NUM-$1") - (filter #(re-find #"[0-9a-zA-Z*+!_'?<>=-]{1}" %)) - (apply str)))] - ;; (when (not= sanitized-kw e) (prn :sanitize e :-> sanitized-kw)) - (if (not= sanitized-kw e) sanitized-kw e)) - e)) - m)) + (let [initial-version (:kv/value (first (filter #(= :logseq.kv/graph-initial-schema-version (:db/ident %)) + (::kv-values m))))] + ;; Only ignore patch if initial version is > 64.8 since this fix started with 64.9 + (if (some-> initial-version (db-schema/compare-schema-version {:major 64 :minor 8}) pos?) + m + (walk/postwalk + (fn [e] + (if (and (keyword? e) (some-> (namespace e) (string/starts-with? "user."))) + ;; Copied from create-db-ident-from-name since this may be shortlived + (let [sanitized-kw (keyword (namespace e) + (->> (string/replace-first (name e) #"^(\d)" "NUM-$1") + (filter #(re-find #"[0-9a-zA-Z*+!_'?<>=-]{1}" %)) + (apply str)))] + ;; (when (not= sanitized-kw e) (prn :sanitize e :-> sanitized-kw)) + (if (not= sanitized-kw e) sanitized-kw e)) + e)) + m)))) (defn- ensure-export-is-valid "Checks that export map is usable by sqlite.build including checking that From dd94fbda9ceaf74ce0810ef042e254fdb6154228 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 10:06:17 -0400 Subject: [PATCH 21/48] fix: lints --- deps/db/src/logseq/db/frontend/content.cljs | 3 +-- src/main/frontend/components/editor.cljs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/content.cljs b/deps/db/src/logseq/db/frontend/content.cljs index 3adbdc0d4b..4bdd0e7111 100644 --- a/deps/db/src/logseq/db/frontend/content.cljs +++ b/deps/db/src/logseq/db/frontend/content.cljs @@ -4,8 +4,7 @@ [datascript.core :as d] [logseq.common.util :as common-util] [logseq.common.util.page-ref :as page-ref] - [logseq.db.common.entity-util :as common-entity-util] - [logseq.db.frontend.entity-util :as entity-util])) + [logseq.db.common.entity-util :as common-entity-util])) ;; [[uuid]] (def id-ref-pattern diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 2e6ef40a36..ca1970d14e 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -31,7 +31,6 @@ [logseq.common.util.page-ref :as page-ref] [logseq.db :as ldb] [logseq.db.frontend.class :as db-class] - [logseq.db.frontend.content :as db-content] [logseq.graph-parser.property :as gp-property] [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] From 236c4e74d3e74f29f75c336b43c85908a4db5ec1 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 22:34:11 +0800 Subject: [PATCH 22/48] fix: drag drop doesn't work --- src/main/frontend/components/block.cljs | 3 +-- src/main/frontend/components/container.cljs | 5 +++-- src/main/frontend/components/editor.cljs | 2 +- src/main/frontend/handler/editor.cljs | 8 +++++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index c08a767979..87ecc1d47a 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2046,7 +2046,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) @@ -2165,7 +2164,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") diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index c4cbc197e0..90499ba362 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -930,8 +930,9 @@ nil) (defn- on-mouse-up - [_e] - (editor-handler/show-action-bar!)) + [e] + (when-not (.closest (.-target e) ".block-control-wrap") + (editor-handler/show-action-bar!))) (rum/defcs ^:large-vars/cleanup-todo root-container < rum/reactive (mixins/event-mixin diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index ca1970d14e..926a61bf93 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -133,7 +133,7 @@ :other-attrs {:block/link (:db/id page')}})))) (page-handler/on-chosen-handler input id pos format))) -(rum/defc page-search-aux +(rum/defc ^:large-vars/cleanup-todo page-search-aux [id format embed? db-tag? q current-pos input pos] (let [db-based? (config/db-based-graph? (state/get-current-repo)) q (string/trim q) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index bca2fe84e3..1b015f647f 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -35,7 +35,6 @@ [frontend.modules.outliner.op :as outliner-op] [frontend.modules.outliner.tree :as tree] [frontend.modules.outliner.ui :as ui-outliner-tx] - [frontend.util.ref :as ref] [frontend.search :as search] [frontend.state :as state] [frontend.template :as template] @@ -44,6 +43,7 @@ [frontend.util.file-based.drawer :as drawer] [frontend.util.keycode :as keycode] [frontend.util.list :as list] + [frontend.util.ref :as ref] [frontend.util.text :as text-util] [frontend.util.thingatpt :as thingatpt] [goog.dom :as gdom] @@ -1249,8 +1249,10 @@ (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 (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] From 2ece50628bf6256077b281a15ecddff1175bd493 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 10:36:33 -0400 Subject: [PATCH 23/48] fix: large component --- src/main/frontend/components/editor.cljs | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 926a61bf93..613f65f36c 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -133,7 +133,21 @@ :other-attrs {:block/link (:db/id page')}})))) (page-handler/on-chosen-handler input id pos format))) -(rum/defc ^:large-vars/cleanup-todo page-search-aux +(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)) q (string/trim q) @@ -156,25 +170,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' From f9834d95c61574cff7b6fa800ea2adeb8740815c Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 22:43:15 +0800 Subject: [PATCH 24/48] chore: bump to 0.10.11 --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 8 ++++---- resources/forge.config.js | 2 +- resources/package.json | 2 +- src/main/frontend/version.cljs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 062d33cc77..d587b026b9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.logseq.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 84 - versionName "0.10.10" + versionCode 86 + versionName "0.10.11" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index cfb09e7685..28593eb283 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -519,7 +519,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.10.10; + MARKETING_VERSION = 0.10.11; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -546,7 +546,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.10.10; + MARKETING_VERSION = 0.10.11; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; @@ -571,7 +571,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.10.10; + MARKETING_VERSION = 0.10.11; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; @@ -598,7 +598,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.10.10; + MARKETING_VERSION = 0.10.11; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/resources/forge.config.js b/resources/forge.config.js index 702107c6f9..c9a1fff1ef 100644 --- a/resources/forge.config.js +++ b/resources/forge.config.js @@ -5,7 +5,7 @@ module.exports = { packagerConfig: { name: 'Logseq', icon: './icons/logseq_big_sur.icns', - buildVersion: "85", + buildVersion: 86, protocols: [ { "protocol": "logseq", diff --git a/resources/package.json b/resources/package.json index 1ece7047d8..d19fd3788c 100644 --- a/resources/package.json +++ b/resources/package.json @@ -1,7 +1,7 @@ { "name": "Logseq", "productName": "Logseq", - "version": "0.10.10", + "version": "0.10.11", "main": "electron.js", "author": "Logseq", "license": "AGPL-3.0", diff --git a/src/main/frontend/version.cljs b/src/main/frontend/version.cljs index ad6cde7f3b..0c8ca61941 100644 --- a/src/main/frontend/version.cljs +++ b/src/main/frontend/version.cljs @@ -1,3 +1,3 @@ (ns ^:no-doc frontend.version) -(defonce version "0.10.10") +(defonce version "0.10.11") From a2f0f4ca2c9d8f2b3dcc8e2fdf403966da0aea95 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 22:55:29 +0800 Subject: [PATCH 25/48] chore: remove debug --- src/main/frontend/components/right_sidebar.cljs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/frontend/components/right_sidebar.cljs b/src/main/frontend/components/right_sidebar.cljs index 50d9b95eb3..790fcd7aae 100644 --- a/src/main/frontend/components/right_sidebar.cljs +++ b/src/main/frontend/components/right_sidebar.cljs @@ -211,7 +211,6 @@ (p/let [item ( (when (zero? idx) (drop-indicator (dec idx) drag-to)) From c22f8693ccabae2589a14ef674aebe99d4742470 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 23:40:55 +0800 Subject: [PATCH 26/48] fix: buildVersion should be a string --- resources/forge.config.js | 2 +- scripts/bump-version.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/forge.config.js b/resources/forge.config.js index c9a1fff1ef..aa91c34ea4 100644 --- a/resources/forge.config.js +++ b/resources/forge.config.js @@ -5,7 +5,7 @@ module.exports = { packagerConfig: { name: 'Logseq', icon: './icons/logseq_big_sur.icns', - buildVersion: 86, + buildVersion: '86', protocols: [ { "protocol": "logseq", diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index cbb6581b3c..801807f58d 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -58,7 +58,7 @@ $SED -i 's/defonce version ".*"/defonce version "'${NEW_VERSION}'"/g' src/main/f $SED -i 's/"version": ".*"/"version": "'${NEW_VERSION}'"/g' resources/package.json $SED -i 's/versionName ".*"/versionName "'${NEW_VERSION}'"/g' android/app/build.gradle $SED -i 's/versionCode .*/versionCode '${NEW_VERSION_CODE}'/g' android/app/build.gradle -$SED -i 's/buildVersion: .*/buildVersion: '${NEW_VERSION_CODE}',/g' resources/forge.config.js +$SED -i 's/buildVersion: .*/buildVersion: "'${NEW_VERSION_CODE}'",/g' resources/forge.config.js $SED -i 's/MARKETING_VERSION = .*;/MARKETING_VERSION = '${NEW_VERSION}';/g' ios/App/App.xcodeproj/project.pbxproj git --no-pager diff -U0 From 4b1c79a931389a70c6bc38034823199964657d45 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 19 May 2025 23:36:55 +0800 Subject: [PATCH 27/48] enhance: no need to input space before / and # command triggers --- src/main/frontend/commands.cljs | 10 +++------ src/main/frontend/handler/editor.cljs | 31 ++++++++++++--------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/main/frontend/commands.cljs b/src/main/frontend/commands.cljs index 32080083a6..5e2114efb7 100644 --- a/src/main/frontend/commands.cljs +++ b/src/main/frontend/commands.cljs @@ -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] @@ -473,7 +473,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])))))] @@ -748,11 +748,7 @@ (string/replace-first (subs edit-content pos) (file-based-status/marker-pattern format) (str marker " ")))] - (state/set-edit-content! input-id new-value) - (let [new-pos (compute-pos-delta-when-change-marker - edit-content marker (dec slash-pos))] - ;; TODO: any performance issue? - (js/setTimeout #(cursor/move-cursor-to current-input new-pos) 10)))))) + (state/set-edit-content! input-id new-value))))) (defn- db-based-set-status [status] diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 1b015f647f..d408abcb86 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1816,14 +1816,10 @@ (not (and (config/db-based-graph? repo) (re-find #"#\S+" value)))) - ; don't auto-save for page's properties block + ;; don't auto-save for page's properties block (save-current-block! {:skip-properties? true}))) 450))))) -(defn- start-of-new-word? - [input pos] - (contains? #{" " "\t"} (get (.-value input) (- pos 2)))) - (defn handle-last-input [] (let [input (state/get-input) input-id (state/get-edit-input-id) @@ -1844,12 +1840,8 @@ (p/let [_ (state/pub-event! [:editor/toggle-own-number-list edit-block])] (state/set-edit-content! input-id "")) - (and (= last-input-char commands/command-trigger) - (or (re-find #"(?m)^/" (str (.-value input))) (start-of-new-word? input pos))) - (do - (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) - (commands/reinit-matched-commands!) - (state/set-editor-show-commands!)) + (= last-prev-input-char last-input-char commands/command-trigger) + (state/clear-editor-action!) (and (= last-input-char last-prev-input-char commands/colon) (or (nil? prev-prev-input-char) @@ -1880,11 +1872,7 @@ (state/clear-editor-action!) ;; Open "Search page or New page" auto-complete - (and (= last-input-char commands/hashtag) - ;; Only trigger at beginning of a line, before whitespace or after a reference - (or (re-find #"(?m)^#" (str (.-value input))) - (start-of-new-word? input pos) - (and db-based? (= page-ref/right-brackets (common-util/safe-subs (str (.-value input)) (- pos 3) (dec pos)))))) + (= last-input-char commands/hashtag) (do (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) (state/set-editor-last-pos! pos) @@ -2896,6 +2884,15 @@ (state/set-state! :editor/start-pos pos)) (cond + (and (= key commands/command-trigger) + ;; FIXME: surround-by? doesn't work on `handle-last-input` + (not (or (surround-by? input "http:" "") + (surround-by? input "https:" "")))) + (do + (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) + (commands/reinit-matched-commands!) + (state/set-editor-show-commands!)) + (and (= :page-search (state/get-editor-action)) (= key commands/hashtag)) (do @@ -3014,7 +3011,7 @@ (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})) (when (and (not editor-action) (not non-enter-processed?)) (cond - ;; When you type text inside square brackets + ;; When you type text inside square brackets (and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp" "Escape"} k)) (wrapped-by? input page-ref/left-brackets page-ref/right-brackets)) (let [orig-pos (cursor/get-caret-pos input) From 9deb7817487e3afe8af9b7337959a731e0204a05 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Tue, 20 May 2025 00:55:33 +0800 Subject: [PATCH 28/48] test(e2e): add logseq.e2e.rtc-extra-test --- clj-e2e/dev/user.clj | 1 + clj-e2e/test/logseq/e2e/rtc_extra_test.clj | 47 ++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/clj-e2e/dev/user.clj b/clj-e2e/dev/user.clj index 6190fc7d52..ec02bac9fe 100644 --- a/clj-e2e/dev/user.clj +++ b/clj-e2e/dev/user.clj @@ -12,6 +12,7 @@ [logseq.e2e.plugins-basic-test] [logseq.e2e.reference-basic-test] [logseq.e2e.rtc-basic-test] + [logseq.e2e.rtc-extra-test] [logseq.e2e.util :as util] [wally.main :as w] [wally.repl :as repl])) diff --git a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj index a600e6619a..b07eb2cfe1 100644 --- a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj +++ b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj @@ -1,8 +1,47 @@ (ns logseq.e2e.rtc-extra-test (:require - [clojure.test :refer [deftest testing is use-fixtures]])) + [clojure.test :refer [deftest testing is use-fixtures run-tests]] + [com.climate.claypoole :as cp] + [logseq.e2e.fixtures :as fixtures :refer [*page1 *page2]] + [logseq.e2e.graph :as graph] + [logseq.e2e.util :as util] + [wally.main :as w] + [wally.repl :as repl] + [logseq.e2e.block :as b])) +(use-fixtures :once fixtures/open-2-pages) -(deftest name-test - (testing "Context of the test assertions" - (is true))) +(defn- offline + [offline?] + (.setOffline (.context (w/get-page)) offline?)) + +(defn- wait-for-ops-synced + [] + (w/wait-for "button.cloud.on.queuing" {:timeout 1000}) + (w/wait-for "button.cloud.on.idle" {:timeout 5000})) + +(deftest rtc-extra-test + (let [graph-name (str "rtc-extra-test-graph-" (.toEpochMilli (java.time.Instant/now)))] + (testing "open 2 app instances, add a rtc graph, check this graph available on other instance" + (cp/prun! + 2 + #(w/with-page % + (util/login-test-account)) + [@*page1 @*page2]) + (w/with-page @*page1 + (graph/new-graph graph-name true)) + (w/with-page @*page2 + (graph/wait-for-remote-graph graph-name) + (graph/switch-graph graph-name true))) + (testing "rtc-stop app1, update app2, then rtc-start on app1" + (w/with-page @*page1 + (offline true)) + (w/with-page @*page2 + (dotimes [_i 3] + (b/new-blocks (map #(str "b" %) (range 10))) + (wait-for-ops-synced)) + ;; TODO: more operations + (repl/pause) + ) + ) + )) From d92607e0c0f3c7446450cb720e843a765b93425f Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 01:10:17 +0800 Subject: [PATCH 29/48] Revert "enhance: no need to input space before / and # command triggers" This reverts commit 4b1c79a931389a70c6bc38034823199964657d45. --- src/main/frontend/commands.cljs | 6 +++++- src/main/frontend/handler/editor.cljs | 31 +++++++++++++++------------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/main/frontend/commands.cljs b/src/main/frontend/commands.cljs index 5e2114efb7..1d424a03d7 100644 --- a/src/main/frontend/commands.cljs +++ b/src/main/frontend/commands.cljs @@ -748,7 +748,11 @@ (string/replace-first (subs edit-content pos) (file-based-status/marker-pattern format) (str marker " ")))] - (state/set-edit-content! input-id new-value))))) + (state/set-edit-content! input-id new-value) + (let [new-pos (compute-pos-delta-when-change-marker + edit-content marker (dec slash-pos))] + ;; TODO: any performance issue? + (js/setTimeout #(cursor/move-cursor-to current-input new-pos) 10)))))) (defn- db-based-set-status [status] diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index d408abcb86..1b015f647f 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1816,10 +1816,14 @@ (not (and (config/db-based-graph? repo) (re-find #"#\S+" value)))) - ;; don't auto-save for page's properties block + ; don't auto-save for page's properties block (save-current-block! {:skip-properties? true}))) 450))))) +(defn- start-of-new-word? + [input pos] + (contains? #{" " "\t"} (get (.-value input) (- pos 2)))) + (defn handle-last-input [] (let [input (state/get-input) input-id (state/get-edit-input-id) @@ -1840,8 +1844,12 @@ (p/let [_ (state/pub-event! [:editor/toggle-own-number-list edit-block])] (state/set-edit-content! input-id "")) - (= last-prev-input-char last-input-char commands/command-trigger) - (state/clear-editor-action!) + (and (= last-input-char commands/command-trigger) + (or (re-find #"(?m)^/" (str (.-value input))) (start-of-new-word? input pos))) + (do + (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) + (commands/reinit-matched-commands!) + (state/set-editor-show-commands!)) (and (= last-input-char last-prev-input-char commands/colon) (or (nil? prev-prev-input-char) @@ -1872,7 +1880,11 @@ (state/clear-editor-action!) ;; Open "Search page or New page" auto-complete - (= last-input-char commands/hashtag) + (and (= last-input-char commands/hashtag) + ;; Only trigger at beginning of a line, before whitespace or after a reference + (or (re-find #"(?m)^#" (str (.-value input))) + (start-of-new-word? input pos) + (and db-based? (= page-ref/right-brackets (common-util/safe-subs (str (.-value input)) (- pos 3) (dec pos)))))) (do (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) (state/set-editor-last-pos! pos) @@ -2884,15 +2896,6 @@ (state/set-state! :editor/start-pos pos)) (cond - (and (= key commands/command-trigger) - ;; FIXME: surround-by? doesn't work on `handle-last-input` - (not (or (surround-by? input "http:" "") - (surround-by? input "https:" "")))) - (do - (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)}) - (commands/reinit-matched-commands!) - (state/set-editor-show-commands!)) - (and (= :page-search (state/get-editor-action)) (= key commands/hashtag)) (do @@ -3011,7 +3014,7 @@ (state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})) (when (and (not editor-action) (not non-enter-processed?)) (cond - ;; When you type text inside square brackets + ;; When you type text inside square brackets (and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp" "Escape"} k)) (wrapped-by? input page-ref/left-brackets page-ref/right-brackets)) (let [orig-pos (cursor/get-caret-pos input) From 6182c2f36a0c35bc433baa32edcdcf7858f5c551 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 01:44:44 +0800 Subject: [PATCH 30/48] fix: e2e tests --- clj-e2e/test/logseq/e2e/commands_basic_test.clj | 2 +- deps/db/src/logseq/db/frontend/entity_util.cljs | 3 +-- src/main/frontend/handler/route.cljs | 2 +- src/main/frontend/state.cljs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/clj-e2e/test/logseq/e2e/commands_basic_test.clj b/clj-e2e/test/logseq/e2e/commands_basic_test.clj index 16d789dbc5..486615de88 100644 --- a/clj-e2e/test/logseq/e2e/commands_basic_test.clj +++ b/clj-e2e/test/logseq/e2e/commands_basic_test.clj @@ -43,7 +43,7 @@ (k/enter) (is (string/includes? (util/get-edit-content) "[[")) (util/exit-edit) - (is (= "b1" (util/get-text ".block-ref")))))) + (is (= "b1" (.textContent (second (w/query "a.page-ref")))))))) (deftest link-test (testing "/link" diff --git a/deps/db/src/logseq/db/frontend/entity_util.cljs b/deps/db/src/logseq/db/frontend/entity_util.cljs index 2a92fb003d..f01ad9f464 100644 --- a/deps/db/src/logseq/db/frontend/entity_util.cljs +++ b/deps/db/src/logseq/db/frontend/entity_util.cljs @@ -65,8 +65,7 @@ (when page (if (string? page) (string/starts-with? page "$$$") - (when (and (or (map? page) (de/entity? page)) - (not (property? page))) + (when (or (map? page) (de/entity? page)) (:logseq.property/hide? page)))))) (defn object? diff --git a/src/main/frontend/handler/route.cljs b/src/main/frontend/handler/route.cljs index 21c2bf8cf5..c8693877b1 100644 --- a/src/main/frontend/handler/route.cljs +++ b/src/main/frontend/handler/route.cljs @@ -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)))] diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index e8ce5cdbe5..150e120a64 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -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 From 9475c7a08e2b6fc090dc3719c5d6a58aa654bb11 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 02:21:52 +0800 Subject: [PATCH 31/48] fix: recursive ref not block e2e tests --- src/main/frontend/components/block.cljs | 140 +++++++++++++----------- 1 file changed, 76 insertions(+), 64 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 87ecc1d47a..5387cf3819 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -976,8 +976,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] @@ -1067,51 +1068,59 @@ (declare block-positioned-properties) (rum/defc page-reference < rum/reactive db-mixins/query "Component for page reference" - [{:keys [html-export? nested-link? show-brackets? id] :as config} uuid-or-title* 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*) 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) + 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) + #{uuid-or-title*} + (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) - (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 - [: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])]))))) + :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] @@ -1319,29 +1328,32 @@ (rum/defc block-reference [config id label] - (if (config/db-based-graph?) - (page-reference config id label) - (let [block-id (and id (if (uuid? id) id (parse-uuid id))) - [block set-block!] (hooks/use-state (db/entity [:block/uuid block-id])) - self-reference? (when (set? (:ref-set config)) - (contains? (:ref-set config) block-id))] - (hooks/use-effect! - (fn [] - (p/let [block (db-async/ Date: Tue, 20 May 2025 02:43:38 +0800 Subject: [PATCH 32/48] fix: reference e2e tests --- clj-e2e/test/logseq/e2e/reference_basic_test.clj | 6 +++--- src/main/frontend/components/block.cljs | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/clj-e2e/test/logseq/e2e/reference_basic_test.clj b/clj-e2e/test/logseq/e2e/reference_basic_test.clj index 2300dcbc56..216d1f918f 100644 --- a/clj-e2e/test/logseq/e2e/reference_basic_test.clj +++ b/clj-e2e/test/logseq/e2e/reference_basic_test.clj @@ -43,7 +43,7 @@ (b/wait-editor-text "b2") (b/paste) (util/exit-edit) - (b/assert-blocks-visible ["b1b2" "b2b1"]))) + (b/assert-blocks-visible ["b1[[b2]]" "b2[[b1]]"]))) (deftest parent-reference (testing "parent reference" @@ -59,7 +59,7 @@ (b/wait-editor-text "b2") (b/paste) (util/exit-edit) - (b/assert-blocks-visible ["b1b2" "b2b1"]))) + (b/assert-blocks-visible ["b1[[b2]]" "b2[[b1]]"]))) (deftest cycle-reference (testing "cycle reference" @@ -80,6 +80,6 @@ (assert/assert-editor-mode) (b/paste) (util/exit-edit) - (b/assert-blocks-visible ["b1b3b2" "b2b1b3" "b3b2b1"]))) + (b/assert-blocks-visible ["b1[[b3[[b2]]]]" "b2[[b1[[b3]]]]" "b3[[b2[[b1]]]]"]))) ;; TODO: page references diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 5387cf3819..385f240f4a 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -1071,7 +1071,10 @@ [{: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*) self-reference? (when (set? (:ref-set config*)) (contains? (:ref-set config*) uuid-or-title))] @@ -1079,8 +1082,8 @@ (let [config (update config* :ref-set (fn [s] (let [bid (:block/uuid (:block config*))] (if (nil? s) - #{uuid-or-title*} - (conj s bid uuid-or-title*))))) + #{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) From a55e43e8175e53c11bf34540c7eea8714b8cbe88 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 02:48:20 +0800 Subject: [PATCH 33/48] chore: set clj-e2e tests timeout to 30m --- .github/workflows/clj-e2e.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clj-e2e.yml b/.github/workflows/clj-e2e.yml index 120a6dd4c1..1b2b7c8e82 100644 --- a/.github/workflows/clj-e2e.yml +++ b/.github/workflows/clj-e2e.yml @@ -83,10 +83,10 @@ jobs: ls -lR ./public - name: Run e2e tests - run: cd clj-e2e && bb dev + run: cd clj-e2e && timeout 30m bb dev env: DEBUG: "pw:api" - + - name: Collect screenshots if: ${{ failure() }} uses: actions/upload-artifact@v4 From fa869a4c774740c73a48e81828e89e643ff76f00 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 19 May 2025 15:28:21 -0400 Subject: [PATCH 34/48] chore: temporarily disable nightly build to allow testing of 0.10.11-rc1 --- .github/workflows/build-desktop-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-desktop-release.yml b/.github/workflows/build-desktop-release.yml index 3aa4cabd9f..5505da9dfa 100644 --- a/.github/workflows/build-desktop-release.yml +++ b/.github/workflows/build-desktop-release.yml @@ -43,8 +43,8 @@ on: type: boolean required: true default: true - schedule: # Every workday at the 2 P.M. (UTC) we run a scheduled nightly build - - cron: '0 14 * * MON-FRI' + # schedule: # Every workday at the 2 P.M. (UTC) we run a scheduled nightly build + # - cron: '0 14 * * MON-FRI' env: CLOJURE_VERSION: '1.11.1.1413' From 789834a9af9633d515179740feac7f4809bd92cf Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 05:53:34 +0800 Subject: [PATCH 35/48] fix: db missing addresses This commit uses sql to ensure deleting addresses are not referenced in any row. --- deps.edn | 2 +- deps/db/deps.edn | 2 +- deps/outliner/deps.edn | 2 +- src/main/frontend/worker/db_worker.cljs | 37 +++++++++++++++++-------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/deps.edn b/deps.edn index f646eba0d4..eec4e506db 100644 --- a/deps.edn +++ b/deps.edn @@ -5,7 +5,7 @@ :sha "5d672bf84ed944414b9f61eeb83808ead7be9127"} datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} + :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} datascript-transit/datascript-transit {:mvn/version "0.3.0"} borkdude/rewrite-edn {:mvn/version "0.4.9"} diff --git a/deps/db/deps.edn b/deps/db/deps.edn index b749423da2..8bc0f21be5 100644 --- a/deps/db/deps.edn +++ b/deps/db/deps.edn @@ -1,7 +1,7 @@ {:deps ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} + :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} datascript-transit/datascript-transit {:mvn/version "0.3.0" :exclusions [datascript/datascript]} cljs-bean/cljs-bean {:mvn/version "1.5.0"} diff --git a/deps/outliner/deps.edn b/deps/outliner/deps.edn index e1bcd0bd34..d06c0d9c3a 100644 --- a/deps/outliner/deps.edn +++ b/deps/outliner/deps.edn @@ -1,7 +1,7 @@ {:deps ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} + :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} com.cognitect/transit-cljs {:mvn/version "0.8.280"} ;; Any other deps should be added here and to nbb.edn diff --git a/src/main/frontend/worker/db_worker.cljs b/src/main/frontend/worker/db_worker.cljs index bf65108030..c93f8b3d51 100644 --- a/src/main/frontend/worker/db_worker.cljs +++ b/src/main/frontend/worker/db_worker.cljs @@ -188,6 +188,21 @@ :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*] @@ -198,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" From 5746e03a0ab8dfd827d8cdeb367fddf0ed9fc831 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 06:07:34 +0800 Subject: [PATCH 36/48] chore: downgrade persistent-sorted-set to 0.0.8 CI error https://github.com/logseq/logseq/actions/runs/15124002453/job/42512483343 --- deps.edn | 2 +- deps/db/deps.edn | 2 +- deps/outliner/deps.edn | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index eec4e506db..f646eba0d4 100644 --- a/deps.edn +++ b/deps.edn @@ -5,7 +5,7 @@ :sha "5d672bf84ed944414b9f61eeb83808ead7be9127"} datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} + :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} datascript-transit/datascript-transit {:mvn/version "0.3.0"} borkdude/rewrite-edn {:mvn/version "0.4.9"} diff --git a/deps/db/deps.edn b/deps/db/deps.edn index 8bc0f21be5..b749423da2 100644 --- a/deps/db/deps.edn +++ b/deps/db/deps.edn @@ -1,7 +1,7 @@ {:deps ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} + :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} datascript-transit/datascript-transit {:mvn/version "0.3.0" :exclusions [datascript/datascript]} cljs-bean/cljs-bean {:mvn/version "1.5.0"} diff --git a/deps/outliner/deps.edn b/deps/outliner/deps.edn index d06c0d9c3a..e1bcd0bd34 100644 --- a/deps/outliner/deps.edn +++ b/deps/outliner/deps.edn @@ -1,7 +1,7 @@ {:deps ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork - :sha "94b68a02ad8e7354c84c1b3cf3a1b33e19258f41"} + :sha "4b1f15f05a6b4a718a62c247956206480e361ea6"} com.cognitect/transit-cljs {:mvn/version "0.8.280"} ;; Any other deps should be added here and to nbb.edn From ef3a09e01c5bbfa4d46bfd9689d1c8fd124f4e74 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Tue, 20 May 2025 12:57:44 +0800 Subject: [PATCH 37/48] test(e2e): update logseq.e2e.rtc-extra-test --- clj-e2e/src/logseq/e2e/rtc.clj | 1 + clj-e2e/test/logseq/e2e/rtc_extra_test.clj | 46 +++++++++++++--------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/clj-e2e/src/logseq/e2e/rtc.clj b/clj-e2e/src/logseq/e2e/rtc.clj index 2c496f4adf..d12ef24839 100644 --- a/clj-e2e/src/logseq/e2e/rtc.clj +++ b/clj-e2e/src/logseq/e2e/rtc.clj @@ -33,6 +33,7 @@ (defn wait-tx-update-to [new-tx] + (assert (int? new-tx)) (loop [i 5] (when (zero? i) (throw (ex-info "wait-tx-update-to" {:update-to new-tx}))) (util/wait-timeout 1000) diff --git a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj index b07eb2cfe1..8885a1d5df 100644 --- a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj +++ b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj @@ -2,23 +2,23 @@ (:require [clojure.test :refer [deftest testing is use-fixtures run-tests]] [com.climate.claypoole :as cp] + [logseq.e2e.block :as b] [logseq.e2e.fixtures :as fixtures :refer [*page1 *page2]] [logseq.e2e.graph :as graph] + [logseq.e2e.rtc :as rtc] [logseq.e2e.util :as util] [wally.main :as w] - [wally.repl :as repl] - [logseq.e2e.block :as b])) + [wally.repl :as repl])) (use-fixtures :once fixtures/open-2-pages) (defn- offline - [offline?] - (.setOffline (.context (w/get-page)) offline?)) - -(defn- wait-for-ops-synced [] - (w/wait-for "button.cloud.on.queuing" {:timeout 1000}) - (w/wait-for "button.cloud.on.idle" {:timeout 5000})) + (.setOffline (.context (w/get-page)) true)) + +(defn- online + [] + (.setOffline (.context (w/get-page)) false)) (deftest rtc-extra-test (let [graph-name (str "rtc-extra-test-graph-" (.toEpochMilli (java.time.Instant/now)))] @@ -34,14 +34,24 @@ (graph/wait-for-remote-graph graph-name) (graph/switch-graph graph-name true))) (testing "rtc-stop app1, update app2, then rtc-start on app1" - (w/with-page @*page1 - (offline true)) + (let [*latest-remote-tx (atom nil)] + (w/with-page @*page1 + (offline)) + (w/with-page @*page2 + (let [{:keys [_local-tx remote-tx]} + (rtc/with-wait-tx-updated + (dotimes [_i 3] + (doseq [i (range 10)] + (b/new-block (str "b" i)) + (util/input-command "Doing"))))] + (reset! *latest-remote-tx remote-tx)) + ;; TODO: more operations + (util/exit-edit)) + (w/with-page @*page1 + (online) + (rtc/wait-tx-update-to @*latest-remote-tx) + ;; TODO: check blocks exist + ))) + (testing "cleanup" (w/with-page @*page2 - (dotimes [_i 3] - (b/new-blocks (map #(str "b" %) (range 10))) - (wait-for-ops-synced)) - ;; TODO: more operations - (repl/pause) - ) - ) - )) + (graph/remove-remote-graph graph-name))))) From 984ac7ae7bee15dc6933934f57dddde21aac5319 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Tue, 20 May 2025 14:31:31 +0800 Subject: [PATCH 38/48] test(e2e): update logseq.e2e.rtc-extra-test (2) --- clj-e2e/dev/user.clj | 5 ++++ clj-e2e/test/logseq/e2e/rtc_extra_test.clj | 32 +++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/clj-e2e/dev/user.clj b/clj-e2e/dev/user.clj index ec02bac9fe..5a77adebfc 100644 --- a/clj-e2e/dev/user.clj +++ b/clj-e2e/dev/user.clj @@ -60,6 +60,11 @@ (->> (future (run-tests 'logseq.e2e.plugins-basic-test)) (swap! *futures assoc :plugins-test))) +(defn run-rtc-extra-test + [] + (->> (future (run-tests 'logseq.e2e.rtc-extra-test)) + (swap! *futures assoc :rtc-extra-test))) + (defn run-all-basic-test [] (run-tests 'logseq.e2e.commands-basic-test diff --git a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj index 8885a1d5df..6373e4b70c 100644 --- a/clj-e2e/test/logseq/e2e/rtc_extra_test.clj +++ b/clj-e2e/test/logseq/e2e/rtc_extra_test.clj @@ -10,7 +10,18 @@ [wally.main :as w] [wally.repl :as repl])) -(use-fixtures :once fixtures/open-2-pages) +(def *graph-name (atom nil)) +(defn cleanup-fixture + [f] + (f) + (w/with-page @*page2 + (assert (some? @*graph-name)) + (graph/remove-remote-graph @*graph-name))) + +(use-fixtures :once + fixtures/open-2-pages + ;; cleanup-fixture + ) (defn- offline [] @@ -20,8 +31,17 @@ [] (.setOffline (.context (w/get-page)) false)) +(defn- insert-task-blocks + [title-prefix] + (doseq [status ["Backlog" "Todo" "Doing" "In review" "Done" "Canceled"] + priority ["No priority" "Low" "Medium" "High" "Urgent"]] + (b/new-block (str title-prefix "-" status "-" priority)) + (util/input-command status) + (util/input-command priority))) + (deftest rtc-extra-test (let [graph-name (str "rtc-extra-test-graph-" (.toEpochMilli (java.time.Instant/now)))] + (reset! *graph-name graph-name) (testing "open 2 app instances, add a rtc graph, check this graph available on other instance" (cp/prun! 2 @@ -33,17 +53,14 @@ (w/with-page @*page2 (graph/wait-for-remote-graph graph-name) (graph/switch-graph graph-name true))) - (testing "rtc-stop app1, update app2, then rtc-start on app1" + (testing "rtc-stop app1, add some task blocks, then rtc-start on app1" (let [*latest-remote-tx (atom nil)] (w/with-page @*page1 (offline)) (w/with-page @*page2 (let [{:keys [_local-tx remote-tx]} (rtc/with-wait-tx-updated - (dotimes [_i 3] - (doseq [i (range 10)] - (b/new-block (str "b" i)) - (util/input-command "Doing"))))] + (insert-task-blocks "t1"))] (reset! *latest-remote-tx remote-tx)) ;; TODO: more operations (util/exit-edit)) @@ -54,4 +71,5 @@ ))) (testing "cleanup" (w/with-page @*page2 - (graph/remove-remote-graph graph-name))))) + (assert (some? @*graph-name)) + (graph/remove-remote-graph @*graph-name))))) From 3c4bd0643a90ca94491f3989f8c0fd906c6616cf Mon Sep 17 00:00:00 2001 From: rcmerci Date: Tue, 20 May 2025 15:54:35 +0800 Subject: [PATCH 39/48] fix: add :block/uuid to :logseq.property/empty-placeholder entity --- deps/db/src/logseq/db/sqlite/create_graph.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/db/src/logseq/db/sqlite/create_graph.cljs b/deps/db/src/logseq/db/sqlite/create_graph.cljs index 08390987c4..b4fcc1e68f 100644 --- a/deps/db/src/logseq/db/sqlite/create_graph.cljs +++ b/deps/db/src/logseq/db/sqlite/create_graph.cljs @@ -201,7 +201,8 @@ (sqlite-util/kv :logseq.kv/graph-initial-schema-version db-schema/version) (sqlite-util/kv :logseq.kv/graph-created-at (common-util/time-ms)) ;; Empty property value used by db.type/ref properties - {:db/ident :logseq.property/empty-placeholder}] + {:db/ident :logseq.property/empty-placeholder + :block/uuid (common-uuid/gen-uuid :builtin-block-uuid :logseq.property/empty-placeholder)}] import-type (into (sqlite-util/import-tx import-type))) initial-files [{:block/uuid (common-uuid/gen-uuid :builtin-block-uuid "logseq/config.edn") From 3fb4ae74ada26fda7e8b68cd1bd6c9d6a60d30c3 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Tue, 20 May 2025 16:03:41 +0800 Subject: [PATCH 40/48] fix: add :block/uuid to :logseq.property/empty-placeholder entity (2) --- deps/db/src/logseq/db/frontend/schema.cljs | 2 +- src/main/frontend/worker/db/migrate.cljs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/schema.cljs b/deps/db/src/logseq/db/frontend/schema.cljs index daf826d256..3260587a98 100644 --- a/deps/db/src/logseq/db/frontend/schema.cljs +++ b/deps/db/src/logseq/db/frontend/schema.cljs @@ -37,7 +37,7 @@ (map (juxt :major :minor) [(parse-schema-version x) (parse-schema-version y)]))) -(def version (parse-schema-version "64.8")) +(def version (parse-schema-version "64.9")) (defn major-version "Return a number. diff --git a/src/main/frontend/worker/db/migrate.cljs b/src/main/frontend/worker/db/migrate.cljs index d81a866a5c..2a6fd9519c 100644 --- a/src/main/frontend/worker/db/migrate.cljs +++ b/src/main/frontend/worker/db/migrate.cljs @@ -859,6 +859,12 @@ :logseq.task/scheduled :logseq.property/scheduled}) conn search-db)) + +(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 @@ -958,8 +964,8 @@ [62 {:fix remove-block-schema}] [63 {:properties [:logseq.property.table/pinned-columns]}] [64 {:fix update-view-filter}] - ;;;; schema-version format: "." - ;;;; int number equals to "" (without ) +;;;; schema-version format: "." +;;;; int number equals to "" (without ) ["64.1" {:properties [:logseq.property.view/group-by-property] :fix add-view-icons}] ["64.2" {:properties [:logseq.property.view/feature-type] @@ -970,7 +976,8 @@ ["64.5" {:fix add-group-by-property-for-list-views}] ["64.6" {:fix cardinality-one-multiple-values}] ["64.7" {:fix rename-repeated-properties}] - ["64.8" {:fix rename-task-properties}]]) + ["64.8" {:fix rename-task-properties}] + ["64.9" {:fix empty-placeholder-add-block-uuid}]]) (let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first) schema-version->updates))) From f4303fdd0493f3f6135e9d75604b8442cc055c6f Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 17:05:41 +0800 Subject: [PATCH 41/48] fix: enable upload asset on web --- src/main/frontend/commands.cljs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/commands.cljs b/src/main/frontend/commands.cljs index 1d424a03d7..55aae931fd 100644 --- a/src/main/frontend/commands.cljs +++ b/src/main/frontend/commands.cljs @@ -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" From 4b766d7525ef1469df69b87f3c771a94bb06854b Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 17:17:02 +0800 Subject: [PATCH 42/48] fix: backspace doesn't move to the prev block when it has properties --- src/main/frontend/util.cljc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/util.cljc b/src/main/frontend/util.cljc index 7a3aef697e..868d85bb7d 100644 --- a/src/main/frontend/util.cljc +++ b/src/main/frontend/util.cljc @@ -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) From 09b6d378944539952ba383cf4cbbb24478488c95 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 18:33:21 +0800 Subject: [PATCH 43/48] enhance(ux): show page actions when hovering title only --- src/main/frontend/components/block.cljs | 8 ++++---- src/main/frontend/components/block.css | 10 ++++++++-- src/main/frontend/components/page.cljs | 20 ++++++++++---------- src/main/frontend/components/page.css | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 385f240f4a..b9a442b631 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -3047,7 +3047,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 @@ -3084,7 +3083,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?) @@ -3639,8 +3641,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) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index 81ea05d9a2..a02e1bfd80 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -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; + } } } diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 3d096756e9..bd6dfba145 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -192,13 +192,13 @@ (rum/defcs page-blocks-cp < rum/reactive db-mixins/query {:will-mount (fn [state] (when-not (config/db-based-graph?) - (let [page-e (first (:rum/args state)) - page-name (:block/name page-e)] - (when (and page-name - (db/journal-page? page-name) - (>= (date/journal-title->int page-name) - (date/journal-title->int (date/today)))) - (state/pub-event! [:journal/insert-template page-name])))) + (let [page-e (first (:rum/args state)) + page-name (:block/name page-e)] + (when (and page-name + (db/journal-page? page-name) + (>= (date/journal-title->int page-name) + (date/journal-title->int (date/today)))) + (state/pub-event! [:journal/insert-template page-name])))) state)} [state block* {:keys [sidebar? whiteboard?] :as config}] (when-let [id (:db/id block*)] @@ -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] diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index 85b65d2e80..9e19a66f58 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -92,7 +92,7 @@ } } - .db-page-title-actions { + .ls-page-title-actions { &:has(button[data-popup-active]) { @apply opacity-100; } From 44bf54ba08969b78f6ac80f52acc1e07d49298da Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 19:14:25 +0800 Subject: [PATCH 44/48] fix: don't show action bar when clicking property value Also, clear selection when clicking property value --- src/main/frontend/components/container.cljs | 6 +++++- .../frontend/components/property/value.cljs | 4 ++-- src/main/frontend/handler/editor.cljs | 17 +++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index 90499ba362..f97c23c157 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -931,7 +931,11 @@ (defn- on-mouse-up [e] - (when-not (.closest (.-target e) ".block-control-wrap") + (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 diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index cd5f6c1043..0f68381f86 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -1156,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) @@ -1171,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") diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 1b015f647f..1bcd487f12 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -2,6 +2,7 @@ (:require [clojure.set :as set] [clojure.string :as string] [clojure.walk :as w] + [dommy.core :as d] [dommy.core :as dom] [electron.ipc :as ipc] [frontend.commands :as commands] @@ -1242,15 +1243,20 @@ (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]) - - (when (seq (state/get-selection-blocks)) + (when (seq (remove (fn [b] (d/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))))) @@ -3325,11 +3331,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")) From 2fbb6d1b7dced675629b1656494f234f5f835fd8 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 19:30:11 +0800 Subject: [PATCH 45/48] enhance(ux): update icon brightness when hovering on it --- src/main/frontend/components/icon.cljs | 7 ++++--- src/main/frontend/ui.css | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/frontend/components/icon.cljs b/src/main/frontend/components/icon.cljs index 5f8305f8fb..d47ac39a0d 100644 --- a/src/main/frontend/components/icon.cljs +++ b/src/main/frontend/components/icon.cljs @@ -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))] diff --git a/src/main/frontend/ui.css b/src/main/frontend/ui.css index c2a102ef54..e3b5d9e3bd 100644 --- a/src/main/frontend/ui.css +++ b/src/main/frontend/ui.css @@ -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; From 30f71b57226921d68fddad56ed8361448043e7ab Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 20 May 2025 09:06:19 -0400 Subject: [PATCH 46/48] fix: new graphs invalid after recent property/empty-placeholder change --- deps/db/src/logseq/db/frontend/malli_schema.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/malli_schema.cljs b/deps/db/src/logseq/db/frontend/malli_schema.cljs index 413a42f59b..d174c2d2ac 100644 --- a/deps/db/src/logseq/db/frontend/malli_schema.cljs +++ b/deps/db/src/logseq/db/frontend/malli_schema.cljs @@ -460,6 +460,7 @@ (def property-value-placeholder [:map [:db/ident [:= :logseq.property/empty-placeholder]] + [:block/uuid :uuid] [:block/tx-id {:optional true} :int]]) (defn entity-dispatch-key [db ent] @@ -486,10 +487,10 @@ :closed-value-block (and (:logseq.property/created-from-property d) (:logseq.property/value d)) :property-value-block - (:block/uuid d) - :block (= (:db/ident d) :logseq.property/empty-placeholder) :property-value-placeholder + (:block/uuid d) + :block (:db/ident d) :db-ident-key-value)] dispatch-key)) From 7bb5fef8cc0519abcd60afd6f0096befc78b1da6 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 20 May 2025 09:13:24 -0400 Subject: [PATCH 47/48] fix: frontend lint --- src/main/frontend/handler/editor.cljs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 1bcd487f12..b0e82c34dd 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -2,7 +2,6 @@ (:require [clojure.set :as set] [clojure.string :as string] [clojure.walk :as w] - [dommy.core :as d] [dommy.core :as dom] [electron.ipc :as ipc] [frontend.commands :as commands] @@ -1255,7 +1254,7 @@ (when-let [timeout @*action-bar-timeout] (js/clearTimeout timeout)) (state/pub-event! [:editor/hide-action-bar]) - (when (seq (remove (fn [b] (d/has-class? b "ls-table-cell")) + (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))))) From fd8a939fc156ea418ca20c9fecd727f59d701be3 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 20 May 2025 23:01:58 +0800 Subject: [PATCH 48/48] fix: recur-replace-uuid-in-block-title when there're ids in title --- deps/db/src/logseq/db/frontend/content.cljs | 38 +++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/content.cljs b/deps/db/src/logseq/db/frontend/content.cljs index 4bdd0e7111..c213bf09c0 100644 --- a/deps/db/src/logseq/db/frontend/content.cljs +++ b/deps/db/src/logseq/db/frontend/content.cljs @@ -172,21 +172,23 @@ ([ent] (recur-replace-uuid-in-block-title ent 10)) ([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)))))) - opts {:replace-block-id? true}] - (loop [result (id-ref->title-ref (:block/title ent) ref-set opts) - last-result nil - depth 0] - (if (or (>= depth max-depth) - (= last-result result)) - result - (recur (id-ref->title-ref result ref-set opts) result (inc depth))))))) + (if (some->> (:block/title ent) (#(re-find id-ref-pattern %))) + (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)))))) + opts {:replace-block-id? true}] + (loop [result (id-ref->title-ref (:block/title ent) ref-set opts) + last-result nil + depth 0] + (if (or (>= depth max-depth) + (= last-result result)) + result + (recur (id-ref->title-ref result ref-set opts) result (inc depth))))) + (:block/title ent))))