Browse Source

Merge branch 'refactor/tag-as-type' into feat/repeated-tasks

Tienson Qin 10 months ago
parent
commit
223928343a
38 changed files with 570 additions and 630 deletions
  1. 1 3
      .carve/ignore
  2. 0 9
      .clj-kondo/funcool/promesa/config.edn
  3. 3 3
      .github/workflows/build-desktop-release.yml
  4. 1 1
      .github/workflows/build-ios-release.yml
  5. 1 1
      .github/workflows/build-ios.yml
  6. 1 0
      .gitignore
  7. 18 2
      deps/db/src/logseq/db/frontend/property.cljs
  8. 1 1
      deps/db/src/logseq/db/frontend/schema.cljs
  9. 23 19
      deps/graph-parser/src/logseq/graph_parser/exporter.cljs
  10. 12 6
      deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs
  11. 3 1
      deps/graph-parser/test/resources/exporter-test-graph/journals/2024_04_01.md
  12. 24 10
      deps/shui/src/logseq/shui/base/core.cljs
  13. 4 0
      deps/shui/src/logseq/shui/ui.cljs
  14. 3 3
      e2e-tests/page-search.spec.ts
  15. 1 1
      package.json
  16. 8 0
      packages/ui/src/index.css
  17. 2 1
      resources/css/shui.css
  18. 2 2
      resources/package.json
  19. 4 0
      src/main/frontend/common.css
  20. 7 5
      src/main/frontend/components/container.cljs
  21. 1 1
      src/main/frontend/components/container.css
  22. 2 16
      src/main/frontend/components/file_sync.css
  23. 50 55
      src/main/frontend/components/header.cljs
  24. 1 1
      src/main/frontend/components/header.css
  25. 4 4
      src/main/frontend/components/plugins.cljs
  26. 4 4
      src/main/frontend/components/right_sidebar.cljs
  27. 8 9
      src/main/frontend/components/rtc/indicator.cljs
  28. 66 67
      src/main/frontend/components/server.cljs
  29. 1 1
      src/main/frontend/handler/events.cljs
  30. 4 3
      src/main/frontend/worker/db/migrate.cljs
  31. 1 1
      src/main/frontend/worker/db_worker.cljs
  32. 20 0
      src/main/frontend/worker/rtc/client_op.cljs
  33. 3 0
      src/main/frontend/worker/rtc/const.cljs
  34. 54 9
      src/main/frontend/worker/rtc/core.cljs
  35. 2 0
      src/main/frontend/worker/rtc/full_upload_download_graph.cljs
  36. 1 1
      src/test/frontend/worker/rtc/rtc_fns_test.cljs
  37. 218 381
      static/yarn.lock
  38. 11 9
      yarn.lock

+ 1 - 3
.carve/ignore

@@ -2,8 +2,6 @@
 electron.core/main
 electron.core/start
 electron.core/stop
-;; repl fn
-electron.search/query
 ;; Used by shadow-cljs
 frontend.core/stop
 ;; For repl
@@ -89,4 +87,4 @@ frontend.worker.rtc.hash/hash-blocks
 ;; Repl fn
 frontend.rum/use-atom-in
 ;; missionary utils
-frontend.common.missionary-util/<!
+frontend.common.missionary-util/<!

+ 0 - 9
.clj-kondo/funcool/promesa/config.edn

@@ -1,9 +0,0 @@
-{:lint-as {promesa.core/->          clojure.core/->
-           promesa.core/->>         clojure.core/->>
-           promesa.core/as->        clojure.core/as->
-           promesa.core/let         clojure.core/let
-           promesa.core/plet        clojure.core/let
-           promesa.core/loop        clojure.core/loop
-           promesa.core/recur       clojure.core/recur
-           promesa.core/with-redefs clojure.core/with-redefs
-           promesa.core/doseq       clojure.core/doseq}}

+ 3 - 3
.github/workflows/build-desktop-release.yml

@@ -390,7 +390,7 @@ jobs:
 
   build-macos-x64:
     needs: [ compile-cljs ]
-    runs-on: macos-latest
+    runs-on: macos-13
 
     steps:
       - name: Download The Static Asset
@@ -466,7 +466,7 @@ jobs:
 
   build-macos-arm64:
     needs: [ compile-cljs ]
-    runs-on: macos-latest
+    runs-on: macos-14
 
     steps:
       - name: Download The Static Asset
@@ -568,7 +568,7 @@ jobs:
       - name: Sign Windows Executable
         run: |
           ls -lah ./builds
-          jsign --storetype ETOKEN --storepass "${PASS}" -t http://timestamp.digicert.com ./builds/*.exe
+          jsign --storetype ETOKEN --storepass "${PASS}" -t http://timestamp.sectigo.com ./builds/*.exe
         env:
           PASS: ${{ secrets.CODE_SIGN_CERTIFICATE_PASSWORD }}
 

+ 1 - 1
.github/workflows/build-ios-release.yml

@@ -17,7 +17,7 @@ env:
 
 jobs:
   build-app:
-    runs-on: macos-latest
+    runs-on: macos-13
     steps:
       - name: Check out Git repository
         uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c  # v3.3.0

+ 1 - 1
.github/workflows/build-ios.yml

@@ -22,7 +22,7 @@ env:
 
 jobs:
   build-app:
-    runs-on: macos-latest
+    runs-on: macos-13
     steps:
       - name: Check out Git repository
         uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c  # v3.3.0

+ 1 - 0
.gitignore

@@ -41,6 +41,7 @@ resources/electron.js
 .clj-kondo/metosin/malli
 .clj-kondo/rewrite-clj
 .clj-kondo/taoensso
+.clj-kondo/funcool
 /libs/dist/
 charlie/
 .vscode

+ 18 - 2
deps/db/src/logseq/db/frontend/property.cljs

@@ -482,7 +482,22 @@
                                 :schema
                                 {:type :map
                                  :hide? false ; TODO: show for debug now, hide it later
-                                 :public? false}}))
+                                 :public? false}}
+   :logseq.user/name {:title "User Name"
+                      :schema
+                      {:type :string
+                       :hide? false
+                       :public? true}}
+   :logseq.user/email {:title "User Email"
+                       :schema
+                       {:type :string
+                        :hide? false
+                        :public? true}}
+   :logseq.user/avatar {:title "User Avatar"
+                        :schema
+                        {:type :string
+                         :hide? false
+                         :public? true}}))
 
 (def built-in-properties
   (->> built-in-properties*
@@ -529,7 +544,8 @@
     "logseq.property.code"
     ;; attribute ns is for db attributes that don't start with :block
     "logseq.property.attribute"
-    "logseq.property.journal" "logseq.property.class" "logseq.property.view"})
+    "logseq.property.journal" "logseq.property.class" "logseq.property.view"
+    "logseq.user"})
 
 (defn logseq-property?
   "Determines if keyword is a logseq property"

+ 1 - 1
deps/db/src/logseq/db/frontend/schema.cljs

@@ -2,7 +2,7 @@
   "Main datascript schemas for the Logseq app"
   (:require [clojure.set :as set]))
 
-(def version 52)
+(def version 53)
 
 ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name".
 (def ^:large-vars/data-var schema

+ 23 - 19
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -48,18 +48,20 @@
             :block/title new-title
             :block/name (common-util/page-name-sanity-lc new-title)})))
 
-(defn- get-page-uuid [page-names-to-uuids page-name]
+(defn- get-page-uuid [page-names-to-uuids page-name ex-data']
   (or (get @page-names-to-uuids (if (string/includes? (str page-name) "#")
                                   (string/lower-case (gp-block/sanitize-hashtag-name page-name))
                                   page-name))
       (throw (ex-info (str "No uuid found for page name " (pr-str page-name))
-                      {:page-name page-name}))))
+                      (merge ex-data' {:page-name page-name})))))
 
 (defn- replace-namespace-with-parent [block page-names-to-uuids]
   (if (:block/namespace block)
     (-> (dissoc block :block/namespace)
         (assoc :logseq.property/parent
-               {:block/uuid (get-page-uuid page-names-to-uuids (get-in block [:block/namespace :block/name]))}))
+               {:block/uuid (get-page-uuid page-names-to-uuids
+                                           (get-in block [:block/namespace :block/name])
+                                           {:block block :block/namespace (:block/namespace block)})}))
     block))
 
 (defn- build-class-ident-name
@@ -197,7 +199,7 @@
                                       (convert-tag? (:block/name %) user-options)
                                       ;; Ignore new class tags from extract e.g. :logseq.class/Journal
                                       (logseq-class-ident? %)))
-                         (map #(vector :block/uuid (get-page-uuid (:page-names-to-uuids per-file-state) (:block/name %))))
+                         (map #(vector :block/uuid (get-page-uuid (:page-names-to-uuids per-file-state) (:block/name %) {:block %})))
                          set)
           page-classes (into #{:logseq.class/Page} db-class/page-children-classes)]
       (cond-> block
@@ -214,7 +216,7 @@
     block))
 
 (defn- add-uuid-to-page-map [m page-names-to-uuids]
-  (assoc m :block/uuid (get-page-uuid page-names-to-uuids (:block/name m))))
+  (assoc m :block/uuid (get-page-uuid page-names-to-uuids (:block/name m) {:block m})))
 
 (defn- content-without-tags-ignore-case
   "Ignore case because tags in content can have any case and still have a valid ref"
@@ -300,12 +302,12 @@
 (defn- update-block-deadline
   ":block/title doesn't contain DEADLINE.* text so unable to detect timestamp
   or repeater usage and notify user that they aren't supported"
-  [block db {:keys [user-config]}]
+  [block page-names-to-uuids {:keys [user-config]}]
   (if-let [date-int (or (:block/deadline block) (:block/scheduled block))]
-    (let [existing-journal-page (ffirst (d/q '[:find (pull ?b [:block/uuid])
-                                               :in $ ?journal-day
-                                               :where [?b :block/journal-day ?journal-day]]
-                                             db date-int))
+    (let [existing-journal-page (some->> (date-time-util/int->journal-title date-int (common-config/get-date-formatter user-config))
+                                         common-util/page-name-sanity-lc
+                                         (get @page-names-to-uuids)
+                                         (hash-map :block/uuid))
           deadline-page (->
                          (or existing-journal-page
                             ;; FIXME: Register new pages so that two different refs to same new page
@@ -519,7 +521,7 @@
   [page-names-to-uuids property-values]
   (set (map #(vector :block/uuid
                      ;; assume for now a ref's :block/name can always be translated by lc helper
-                     (get-page-uuid page-names-to-uuids (common-util/page-name-sanity-lc %)))
+                     (get-page-uuid page-names-to-uuids (common-util/page-name-sanity-lc %) {:original-name %}))
             property-values)))
 
 (defn- handle-changed-property
@@ -619,7 +621,9 @@
       (swap! (:block-properties-text-values import-state)
              assoc
              ;; For pages, valid uuid is in page-names-to-uuids, not in block
-             (if (:block/name block) (get-page-uuid page-names-to-uuids ((some-fn ::original-name :block/name) block)) (:block/uuid block))
+             (if (:block/name block)
+               (get-page-uuid page-names-to-uuids ((some-fn ::original-name :block/name) block) {:block block})
+               (:block/uuid block))
              properties-text-values))
     ;; TODO: Add import support for :template. Ignore for now as they cause invalid property types
     (if (contains? props :template)
@@ -843,7 +847,7 @@
   [{:block/keys [parent] :as block} pre-blocks page-names-to-uuids]
   (cond-> block
     (and (vector? parent) (contains? pre-blocks (second parent)))
-    (assoc :block/parent [:block/uuid (get-page-uuid page-names-to-uuids (second (:block/page block)))])))
+    (assoc :block/parent [:block/uuid (get-page-uuid page-names-to-uuids (second (:block/page block)) {:block block :block/page (:block/page block)})])))
 
 (defn- fix-block-name-lookup-ref
   "Some graph-parser attributes return :block/name as a lookup ref. This fixes
@@ -851,9 +855,9 @@
   [block page-names-to-uuids]
   (cond-> block
     (= :block/name (first (:block/page block)))
-    (assoc :block/page [:block/uuid (get-page-uuid page-names-to-uuids (second (:block/page block)))])
+    (assoc :block/page [:block/uuid (get-page-uuid page-names-to-uuids (second (:block/page block)) {:block block :block/page (:block/page block)})])
     (:block/name (:block/parent block))
-    (assoc :block/parent {:block/uuid (get-page-uuid page-names-to-uuids (:block/name (:block/parent block)))})))
+    (assoc :block/parent {:block/uuid (get-page-uuid page-names-to-uuids (:block/name (:block/parent block)) {:block block :block/parent (:block/parent block)})})))
 
 (defn- build-block-tx
   [db block* pre-blocks {:keys [page-names-to-uuids] :as per-file-state} {:keys [import-state journal-created-ats] :as options}]
@@ -861,7 +865,7 @@
   (let [;; needs to come before update-block-refs to detect new property schemas
         {:keys [block properties-tx]}
         (handle-block-properties block* db page-names-to-uuids (:block/refs block*) options)
-        {block-after-built-in-props :block deadline-properties-tx :properties-tx} (update-block-deadline block db options)
+        {block-after-built-in-props :block deadline-properties-tx :properties-tx} (update-block-deadline block page-names-to-uuids options)
         ;; :block/page should be [:block/page NAME]
         journal-page-created-at (some-> (:block/page block*) second journal-created-ats)
         prepared-block (cond-> block-after-built-in-props
@@ -886,7 +890,7 @@
 (defn- update-page-alias
   [m page-names-to-uuids]
   (update m :block/alias (fn [aliases]
-                           (map #(vector :block/uuid (get-page-uuid page-names-to-uuids (:block/name %)))
+                           (map #(vector :block/uuid (get-page-uuid page-names-to-uuids (:block/name %) {:block %}))
                                 aliases))))
 
 (defn- build-new-page-or-class
@@ -1154,7 +1158,7 @@
              (set/intersection new-properties (set (map keyword (keys existing-pages)))))
         ;; Could do this only for existing pages but the added complexity isn't worth reducing the tx noise
         retract-page-tag-from-properties-tx (map #(vector :db/retract [:block/uuid (:block/uuid %)] :block/tags :logseq.class/Page)
-                                                  (concat property-pages-tx converted-property-pages-tx))
+                                                 (concat property-pages-tx converted-property-pages-tx))
         ;; Save properties on new property pages separately as they can contain new properties and thus need to be
         ;; transacted separately the property pages
         property-page-properties-tx (keep (fn [b]
@@ -1275,7 +1279,7 @@
            pages-tx')
      :retract-page-tag-from-classes-tx
      (mapv #(vector :db/retract [:block/uuid (:block/uuid %)] :block/tags :logseq.class/Page)
-                                              classes-tx)}))
+           classes-tx)}))
 
 (defn add-file-to-db-graph
   "Parse file and save parsed data to the given db graph. Options available:

+ 12 - 6
deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs

@@ -154,12 +154,12 @@
         "Created graph has no validation errors")
     (is (= 0 (count @(:ignored-properties import-state))) "No ignored properties")
     (is (= []
-             (->> (d/q '[:find (pull ?b [:block/title {:block/tags [:db/ident]}])
-                         :where [?b :block/tags :logseq.class/Tag]]
-                       @conn)
-                  (map first)
-                  (remove #(= [{:db/ident :logseq.class/Tag}] (:block/tags %)))))
-          "All classes only have :logseq.class/Tag as their tag (and don't have Page)")))
+           (->> (d/q '[:find (pull ?b [:block/title {:block/tags [:db/ident]}])
+                       :where [?b :block/tags :logseq.class/Tag]]
+                     @conn)
+                (map first)
+                (remove #(= [{:db/ident :logseq.class/Tag}] (:block/tags %)))))
+        "All classes only have :logseq.class/Tag as their tag (and don't have Page)")))
 
 (deftest-async export-basic-graph-with-convert-all-tags
   ;; This graph will contain basic examples of different features to import
@@ -301,6 +301,12 @@
              (readable-properties @conn (db-test/find-block-by-content @conn "only scheduled")))
           "scheduled block converted to correct deadline")
 
+      (is (= 1 (count (d/q '[:find [(pull ?b [*]) ...]
+                             :in $ ?content
+                             :where [?b :block/title ?content]]
+                           @conn "Apr 1st, 2024")))
+          "Only one journal page exists when deadline is on same day as journal")
+
       (is (= {:logseq.task/priority "High"}
              (readable-properties @conn (db-test/find-block-by-content @conn "high priority")))
           "priority block has correct property")

+ 3 - 1
deps/graph-parser/test/resources/exporter-test-graph/journals/2024_04_01.md

@@ -7,4 +7,6 @@
 - DOING [#B] status test
   :LOGBOOK:
   CLOCK: [2024-04-01 Mon 10:39:40]
-  :END:
+  :END:
+- deadline on same day
+  DEADLINE: <2024-04-01 Mon 13:50>

+ 24 - 10
deps/shui/src/logseq/shui/base/core.cljs

@@ -1,7 +1,7 @@
 (ns logseq.shui.base.core
   (:require [logseq.shui.util :as util]
-            [cljs-bean.core :as bean]
-            [rum.core :as rum]))
+            [logseq.shui.icon.v2 :as tabler-icon]
+            [cljs-bean.core :as bean]))
 
 (def button-base (util/lsui-wrap "Button" {:static? false}))
 (def link (util/lsui-wrap "Link"))
@@ -14,11 +14,11 @@
                  {:on-key-down #(case (.-key %)
                                   (" " "Enter")
                                   (do (some-> (.-target %) (.click))
-                                    (.preventDefault %)
-                                    (.stopPropagation %))
+                                      (.preventDefault %)
+                                      (.stopPropagation %))
                                   :dune)}
-                 (map? props)
-                 (merge props))
+                  (map? props)
+                  (merge props))
          children (if (map? props) children (cons props children))]
      [as props' children])))
 
@@ -42,9 +42,23 @@
         on-key-up' (:on-key-up props)
         children (if (map? props) children (cons props children))
         props (assoc (if (map? props) props {})
-                :on-key-up (fn [^js e]
+                     :on-key-up (fn [^js e]
                              ;; TODO: return value
-                             (when (fn? on-key-up') (on-key-up' e))
-                             (when (= "Enter" (.-key e))
-                               (some-> (.-target e) (.click)))))]
+                                  (when (fn? on-key-up') (on-key-up' e))
+                                  (when (= "Enter" (.-key e))
+                                    (some-> (.-target e) (.click)))))]
     (apply button-base props children)))
+
+(defn button-icon
+  [variant icon-name {:keys [icon-props size] :as props} child]
+
+  (button (merge (dissoc props :icon-props :size)
+                 {:variant variant
+                  :data-button :icon
+                  :style (when size {:width size :height size})})
+          [:<>
+           (tabler-icon/root (name icon-name) (merge {:size 20} icon-props)) child]))
+
+(def button-ghost-icon (partial button-icon :ghost))
+(def button-outline-icon (partial button-icon :outline))
+(def button-secondary-icon (partial button-icon :secondary))

+ 4 - 0
deps/shui/src/logseq/shui/ui.cljs

@@ -12,6 +12,10 @@
             [logseq.shui.table.core :as table-core]))
 
 (def button base-core/button)
+(def button-icon base-core/button-icon)
+(def button-ghost-icon base-core/button-ghost-icon)
+(def button-outline-icon base-core/button-outline-icon)
+(def button-secondary-icon base-core/button-secondary-icon)
 (def link base-core/link)
 (def trigger-as base-core/trigger-as)
 (def trigger-child-wrap base-core/trigger-child-wrap)

+ 3 - 3
e2e-tests/page-search.spec.ts

@@ -40,7 +40,7 @@ test('Search page and blocks (diacritics)', async ({ page, block }) => {
 
   // check if diacritics are indexed
   const results = await searchPage(page, 'Einführung in die Allgemeine Sprachwissenschaft' + rand)
-  await expect(results.length).toEqual(5) //  2 block + 1 current page
+  // await expect(results.length).toEqual(5) //  2 block + 1 current page
   await closeSearchBox(page)
 })
 
@@ -62,7 +62,7 @@ test('Search CJK', async ({ page, block }) => {
 
   // check if CJK are indexed
   const results = await searchPage(page, '进度')
-  await expect(results.length).toEqual(4) // 1 page + 1 block + new whiteboard
+  // await expect(results.length).toEqual(4) // 1 page + 1 block + new whiteboard
   await closeSearchBox(page)
 })
 
@@ -169,6 +169,6 @@ async function alias_test(block: Block, page: Page, page_name: string, search_kw
   }
 }
 
-test('page diacritic alias', async ({ block, page }) => {
+test.skip('page diacritic alias', async ({ block, page }) => {
   await alias_test(block, page, "ü", ["ü", "ü", "Ü"])
 })

+ 1 - 1
package.json

@@ -130,7 +130,7 @@
         "d3-force": "3.0.0",
         "diff": "5.0.0",
         "dompurify": "2.4.0",
-        "electron": "28.3.1",
+        "electron": "31.7.5",
         "electron-dl": "3.3.0",
         "emoji-mart": "^5.5.2",
         "fs": "0.0.1-security",

+ 8 - 0
packages/ui/src/index.css

@@ -114,6 +114,14 @@
       --accent: var(--rx-gray-02-hsl);
       --accent-foreground: var(--rx-gray-12-hsl);
     }
+
+    &[data-button="icon"] {
+      @apply box-content p-1 overflow-hidden h-6 w-6;
+
+      &.as-ghost:hover {
+        background: var(--lx-gray-03, var(--ls-tertiary-background-color, var(--rx-gray-03)));
+      }
+    }
   }
 
   .ui__toaster {

+ 2 - 1
resources/css/shui.css

@@ -205,7 +205,8 @@ html[data-theme=dark] {
     }
 
     .cp__header {
-      > .r > div:not(.ui__dropdown-trigger) a.button, button.button {
+      > .r > div:not(.ui__dropdown-trigger) a.button, button.button,
+      .ui__button.as-ghost {
         @apply opacity-60 hover:opacity-90;
       }
     }

+ 2 - 2
resources/package.json

@@ -22,7 +22,7 @@
   },
   "dependencies": {
     "@fastify/cors": "10.0.1",
-    "@logseq/rsapi": "0.0.84",
+    "@logseq/rsapi": "0.0.91",
     "@sentry/electron": "2.5.1",
     "abort-controller": "3.0.0",
     "chokidar": "^3.5.1",
@@ -55,7 +55,7 @@
     "@electron-forge/maker-zip": "^7.3.1",
     "@electron/rebuild": "3.2.10",
     "electron": "31.7.5",
-    "electron-builder": "^22.11.7",
+    "electron-builder": "25.1.8",
     "electron-forge-maker-appimage": "https://github.com/logseq/electron-forge-maker-appimage.git",
     "electron-devtools-installer": "^3.2.0"
   },

+ 4 - 0
src/main/frontend/common.css

@@ -555,6 +555,10 @@ a.fade-link:hover {
   height: 20px;
 }
 
+#head div[data-tooltipped] {
+  display: flex !important;
+}
+
 .svg-small svg {
   transform: scale(0.6);
   display: inline;

+ 7 - 5
src/main/frontend/components/container.cljs

@@ -170,11 +170,11 @@
   [{:keys [on-click-handler class title icon icon-extension? active href shortcut more]}]
   [:div
    {:class (util/classnames [class {:active active}])}
-   [:a.item.group.flex.items-center.text-sm.font-medium.rounded-md
+   [:a.item.group.flex.items-center.text-sm.rounded-md.font-medium
     {:on-click on-click-handler
      :class (when active "active")
      :href href}
-    (ui/icon (str icon) {:extension? icon-extension?})
+    (ui/icon (str icon) {:extension? icon-extension? :size 16})
     [:span.flex-1 title]
     (when shortcut
       [:span.ml-1
@@ -210,7 +210,9 @@
 
 (rum/defc ^:large-vars/cleanup-todo sidebar-navigations
   [{:keys [default-home route-match route-name srs-open? db-based? enable-whiteboards?]}]
-  (let [navs [:whiteboards :flashcards :graph-view :all-pages :tag/tasks :tag/assets]
+  (let [navs (cond->> [:whiteboards :flashcards :graph-view :all-pages]
+               db-based?
+               (into [:tag/tasks :tag/assets]))
         [checked-navs set-checked-navs!] (rum/use-state (or (storage/get :ls-sidebar-navigations)
                                                             [:whiteboards :flashcards :graph-view :all-pages :tag/tasks]))]
 
@@ -338,7 +340,7 @@
                                (let [icon (icon/get-node-icon-cp e {:size 16})]
                                  {:id (str (:db/id e))
                                   :value (:block/uuid e)
-                                  :content [:li.favorite-item (page-name e icon false)]}))
+                                  :content [:li.favorite-item.font-medium (page-name e icon false)]}))
                              favorite-entities)]
          (dnd-component/items favorite-items
                               {:on-drag-end (fn [favorites']
@@ -356,7 +358,7 @@
 
      [:ul.text-sm
       (for [page pages]
-        [:li.recent-item.select-none
+        [:li.recent-item.select-none.font-medium
          {:key (str "recent-" (:db/id page))
           :title (block-handler/block-unique-title page)
           :draggable true

+ 1 - 1
src/main/frontend/components/container.css

@@ -119,7 +119,7 @@
     @apply flex items-center pl-1.5 pr-0.5 h-8 select-none;
 
     .ui__icon {
-      @apply relative flex justify-center w-[20px] text-base mr-2 opacity-80;
+      @apply relative flex justify-center w-[16px] text-base mr-2;
     }
 
     .graph-icon {

+ 2 - 16
src/main/frontend/components/file_sync.css

@@ -6,22 +6,8 @@
 
 .cp__file-sync, .cp__rtc-sync {
   &-indicator {
-    a.cloud {
-      position: relative;
-      opacity: 1 !important;
-      cursor: pointer;
-
-      &:active {
-        opacity: .5 !important;
-      }
-
-      .ti {
-        opacity: .5;
-      }
-
-      &:hover .ti {
-        opacity: .9;
-      }
+    .ui__button.cloud {
+      @apply relative;
 
       &.on {
         &:after {

+ 50 - 55
src/main/frontend/components/header.cljs

@@ -39,14 +39,12 @@
 (rum/defc home-button
   < {:key-fn #(identity "home-button")}
   []
-  (ui/with-shortcut :go/home "left"
-    [:button.button.icon.inline.mx-1
-     {:title (t :home)
-      :on-click #(do
-                   (when (mobile-util/native-iphone?)
-                     (state/set-left-sidebar-open! false))
-                   (route-handler/redirect-to-home!))}
-     (ui/icon "home" {:size ui/icon-size})]))
+  (shui/button-ghost-icon :home
+                          {:title (t :home)
+                           :on-click #(do
+                                        (when (mobile-util/native-iphone?)
+                                          (state/set-left-sidebar-open! false))
+                                        (route-handler/redirect-to-home!))}))
 
 (rum/defcs rtc-collaborators <
   rum/reactive
@@ -68,16 +66,13 @@
         online-users @(::online-users state)]
     (when rtc-graph-id
       [:div.rtc-collaborators.flex.gap-1.text-sm.py-2.bg-gray-01.items-center
-       (shui/button
-        {:variant :ghost
-         :size :sm
-         :class "px-2 opacity-50 hover:opacity-100"
-         :on-click #(shui/dialog-open!
-                     (fn []
-                       [:div.p-2.-mb-8
-                        [:h1.text-3xl.-mt-2.-ml-2 "Collaborators:"]
-                        (settings/settings-collaboration)]))}
-        (shui/tabler-icon "user-plus"))
+       (shui/button-ghost-icon :user-plus
+                               {:on-click #(shui/dialog-open!
+                                            (fn []
+                                              [:div.p-2.-mb-8
+                                               [:h1.text-3xl.-mt-2.-ml-2 "Collaborators:"]
+                                               (settings/settings-collaboration)]))})
+
        (when (seq online-users)
          (for [{user-email :user/email
                 user-name :user/name
@@ -190,51 +185,51 @@
                                :class "w-full"}})]
                  (concat page-menu-and-hr)
                  (remove nil?)))]
-    [:button#dots-menu.button.icon.toolbar-dots-btn
-     {:title (t :header/more)
-      :on-pointer-down (fn [^js e]
-                         (shui/popup-show! (.-target e)
-                                           (fn [{:keys [id]}]
-                                             (for [{:keys [hr item title options icon]} (items)]
-                                               (let [on-click' (:on-click options)
-                                                     href (:href options)]
-                                                 (if hr
-                                                   (shui/dropdown-menu-separator)
-                                                   (shui/dropdown-menu-item
-                                                    (assoc options
-                                                           :on-click (fn [^js e]
-                                                                       (when on-click'
-                                                                         (when-not (false? (on-click' e))
-                                                                           (shui/popup-hide! id)))))
-                                                    (or item
-                                                        (if href
-                                                          [:a.flex.items-center.w-full
-                                                           {:href href :on-click #(shui/popup-hide! id)
-                                                            :style {:color "inherit"}}
-                                                           [:span.flex.items-center.gap-1.w-full
-                                                            icon [:div title]]]
-                                                          [:span.flex.items-center.gap-1.w-full
-                                                           icon [:div title]])))))))
-                                           {:align "end"
-                                            :as-dropdown? true
-                                            :content-props {:class "w-64"
-                                                            :align-offset -32}}))}
-     (ui/icon "dots" {:size ui/icon-size})]))
+
+    (shui/button-ghost-icon :dots
+                            {:title (t :header/more)
+                             :class "toolbar-dots-btn"
+                             :on-pointer-down (fn [^js e]
+                                                (shui/popup-show! (.-target e)
+                                                                  (fn [{:keys [id]}]
+                                                                    (for [{:keys [hr item title options icon]} (items)]
+                                                                      (let [on-click' (:on-click options)
+                                                                            href (:href options)]
+                                                                        (if hr
+                                                                          (shui/dropdown-menu-separator)
+                                                                          (shui/dropdown-menu-item
+                                                                           (assoc options
+                                                                                  :on-click (fn [^js e]
+                                                                                              (when on-click'
+                                                                                                (when-not (false? (on-click' e))
+                                                                                                  (shui/popup-hide! id)))))
+                                                                           (or item
+                                                                               (if href
+                                                                                 [:a.flex.items-center.w-full
+                                                                                  {:href href :on-click #(shui/popup-hide! id)
+                                                                                   :style {:color "inherit"}}
+                                                                                  [:span.flex.items-center.gap-1.w-full
+                                                                                   icon [:div title]]]
+                                                                                 [:span.flex.items-center.gap-1.w-full
+                                                                                  icon [:div title]])))))))
+                                                                  {:align "end"
+                                                                   :as-dropdown? true
+                                                                   :content-props {:class "w-64"
+                                                                                   :align-offset -32}}))})))
 
 (rum/defc back-and-forward
   < {:key-fn #(identity "nav-history-buttons")}
   []
   [:div.flex.flex-row
-
    (ui/with-shortcut :go/backward "bottom"
-     [:button.it.navigation.nav-left.button.icon
-      {:title (t :header/go-back) :on-click #(js/window.history.back)}
-      (ui/icon "arrow-left" {:size ui/icon-size})])
+     (shui/button-ghost-icon :arrow-left
+                             {:title (t :header/go-back) :on-click #(js/window.history.back)
+                              :class "it navigation nav-left"}))
 
    (ui/with-shortcut :go/forward "bottom"
-     [:button.it.navigation.nav-right.button.icon
-      {:title (t :header/go-forward) :on-click #(js/window.history.forward)}
-      (ui/icon "arrow-right" {:size ui/icon-size})])])
+     (shui/button-ghost-icon :arrow-right
+                             {:title (t :header/go-forward) :on-click #(js/window.history.forward)
+                              :class "it navigation nav-right"}))])
 
 (rum/defc updater-tips-new-version
   [t]

+ 1 - 1
src/main/frontend/components/header.css

@@ -177,7 +177,7 @@
 
   &:hover {
     @screen md {
-      background: var(--lx-gray-04, var(--ls-tertiary-background-color, var(--rx-gray-04)));
+      background: var(--lx-gray-03, var(--ls-tertiary-background-color, var(--rx-gray-03)));
     }
   }
 }

+ 4 - 4
src/main/frontend/components/plugins.cljs

@@ -1101,10 +1101,10 @@
                           {:as-dropdown? true
                            :content-props {:class "toolbar-plugins-manager-content"}}))}
 
-     [:a.button.relative.toolbar-plugins-manager-trigger
-      (ui/icon "puzzle" {:size 20})
-      (when badge-updates?
-        (ui/point "bg-red-600.top-1.right-1.absolute" 4 {:style {:margin-right 2 :margin-top 2}}))]]))
+     (shui/button-ghost-icon :puzzle
+                             {:class "flex relative toolbar-plugins-manager-trigger"}
+                             (when badge-updates?
+                               (ui/point "bg-red-600.top-1.right-1.absolute" 4 {:style {:margin-right 2 :margin-top 2}})))]))
 
 (rum/defc header-ui-items-list-wrap
   [children]

+ 4 - 4
src/main/frontend/components/right_sidebar.cljs

@@ -28,10 +28,10 @@
   []
   (when-not (util/sm-breakpoint?)
     (ui/with-shortcut :ui/toggle-right-sidebar "left"
-      [:button.button.icon.toggle-right-sidebar
-       {:title (t :right-side-bar/toggle-right-sidebar)
-        :on-click ui-handler/toggle-right-sidebar!}
-       (ui/icon "layout-sidebar-right" {:size 20})])))
+      (shui/button-ghost-icon :layout-sidebar-right
+                              {:title (t :right-side-bar/toggle-right-sidebar)
+                               :class "toggle-right-sidebar"
+                               :on-click ui-handler/toggle-right-sidebar!}))))
 
 (rum/defc block-cp < rum/reactive
   [repo idx block]

+ 8 - 9
src/main/frontend/components/rtc/indicator.cljs

@@ -169,12 +169,11 @@
           :variant :ghost
           :size    :sm}
          "Uploading..."))
-      [:a.button.cloud
-       {:on-click #(shui/popup-show! (.-target %)
-                                     (details online?)
-                                     {:align "end"})
-        :class    (util/classnames [{:on      (and online? (= :open rtc-state))
-                                     :idle    (and online? (= :open rtc-state) (zero? unpushed-block-update-count))
-                                     :queuing (pos? unpushed-block-update-count)}])}
-       [:span.flex.items-center
-        (ui/icon "cloud" {:size ui/icon-size})]]]]))
+      (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)}])})]]))

+ 66 - 67
src/main/frontend/components/server.cljs

@@ -13,11 +13,11 @@
 
 (rum/defcs panel-of-tokens
   < rum/reactive
-    (rum/local nil ::tokens)
-    {:will-mount
-     (fn [s]
-       (let [*tokens (s ::tokens)]
-         (reset! *tokens (get-in @state/state [:electron/server :tokens])) s))}
+  (rum/local nil ::tokens)
+  {:will-mount
+   (fn [s]
+     (let [*tokens (s ::tokens)]
+       (reset! *tokens (get-in @state/state [:electron/server :tokens])) s))}
   [_state close-panel]
 
   (let [server-state (state/sub :electron/server)
@@ -59,11 +59,11 @@
 
 (rum/defcs panel-of-configs
   < rum/reactive
-    (rum/local nil ::configs)
-    {:will-mount
-     (fn [s]
-       (let [*configs (s ::configs)]
-         (reset! *configs (:electron/server @state/state)) s))}
+  (rum/local nil ::configs)
+  {:will-mount
+   (fn [s]
+     (let [*configs (s ::configs)]
+       (reset! *configs (:electron/server @state/state)) s))}
   [_state close-panel]
 
   (let [server-state (state/sub :electron/server)
@@ -125,13 +125,13 @@
   [server-state]
 
   (rum/use-effect!
-    (fn []
-      (p/let [_ (p/delay 1000)
-              _ (ipc/ipc :server/load-state)]
-        (let [t (js/setTimeout #(when (state/sub [:electron/server :autostart])
-                                  (ipc/ipc :server/do :restart)) 1000)]
-          #(js/clearTimeout t))))
-    [])
+   (fn []
+     (p/let [_ (p/delay 1000)
+             _ (ipc/ipc :server/load-state)]
+       (let [t (js/setTimeout #(when (state/sub [:electron/server :autostart])
+                                 (ipc/ipc :server/do :restart)) 1000)]
+         #(js/clearTimeout t))))
+   [])
 
   (let [{:keys [status error]} server-state
         status   (keyword (util/safe-lower-case status))
@@ -139,55 +139,54 @@
         href     (and running? (str "http://" (:host server-state) ":" (:port server-state)))]
 
     (rum/use-effect!
-      #(when error
-         (notification/show! (str "[Server] " error) :error))
-      [error])
+     #(when error
+        (notification/show! (str "[Server] " error) :error))
+     [error])
 
     [:div.cp__server-indicator
-     [:button.button.icon
-      {:on-click (fn [^js e]
-                   (shui/popup-show!
-                     (.-target e)
-                     (fn [{:keys [_close]}]
-                       (let [items [{:hr? true}
-
-                                    (cond
-                                      running?
-                                      {:title "Stop server"
-                                       :options {:on-click #(ipc/ipc :server/do :stop)}
-                                       :icon [:span.text-red-500.flex.items-center (ui/icon "player-stop")]}
-
-                                      :else
-                                      {:title "Start server"
-                                       :options {:on-click #(ipc/ipc :server/do :restart)}
-                                       :icon [:span.text-green-500.flex.items-center (ui/icon "player-play")]})
-
-                                    {:title "Authorization tokens"
-                                     :options {:on-click #(shui/dialog-open!
-                                                            (fn []
-                                                              (panel-of-tokens shui/dialog-close!)))}
-                                     :icon (ui/icon "key")}
-
-                                    {:title "Server configurations"
-                                     :options {:on-click #(shui/dialog-open!
-                                                            (fn []
-                                                              (panel-of-configs shui/dialog-close!)))}
-                                     :icon (ui/icon "server-cog")}]]
-
-                         (cons
-                           [:div.links-header.flex.justify-center.py-2
-                            [:span.ml-1.text-sm.opacity-70
-                             (if-not running?
-                               (string/upper-case (or (:status server-state) "stopped"))
-                               [:a.hover:underline {:href href} href])]]
-                           (for [{:keys [hr? title options icon]} items]
-                             (cond
-                               hr?
-                               (shui/dropdown-menu-separator)
-
-                               :else
-                               (shui/dropdown-menu-item options
-                                 [:span.flex.items-center icon [:span.pl-1 title]]))))))
-                     {:as-dropdown? true
-                      :content-props {:onClick #(shui/popup-hide!)}}))}
-      (ui/icon (if running? "api" "api-off") {:size 22})]]))
+     (shui/button-ghost-icon (if running? "api" "api-off")
+                             {:on-click (fn [^js e]
+                                          (shui/popup-show!
+                                           (.-target e)
+                                           (fn [{:keys [_close]}]
+                                             (let [items [{:hr? true}
+
+                                                          (cond
+                                                            running?
+                                                            {:title "Stop server"
+                                                             :options {:on-click #(ipc/ipc :server/do :stop)}
+                                                             :icon [:span.text-red-500.flex.items-center (ui/icon "player-stop")]}
+
+                                                            :else
+                                                            {:title "Start server"
+                                                             :options {:on-click #(ipc/ipc :server/do :restart)}
+                                                             :icon [:span.text-green-500.flex.items-center (ui/icon "player-play")]})
+
+                                                          {:title "Authorization tokens"
+                                                           :options {:on-click #(shui/dialog-open!
+                                                                                 (fn []
+                                                                                   (panel-of-tokens shui/dialog-close!)))}
+                                                           :icon (ui/icon "key")}
+
+                                                          {:title "Server configurations"
+                                                           :options {:on-click #(shui/dialog-open!
+                                                                                 (fn []
+                                                                                   (panel-of-configs shui/dialog-close!)))}
+                                                           :icon (ui/icon "server-cog")}]]
+
+                                               (cons
+                                                [:div.links-header.flex.justify-center.py-2
+                                                 [:span.ml-1.text-sm.opacity-70
+                                                  (if-not running?
+                                                    (string/upper-case (or (:status server-state) "stopped"))
+                                                    [:a.hover:underline {:href href} href])]]
+                                                (for [{:keys [hr? title options icon]} items]
+                                                  (cond
+                                                    hr?
+                                                    (shui/dropdown-menu-separator)
+
+                                                    :else
+                                                    (shui/dropdown-menu-item options
+                                                                             [:span.flex.items-center icon [:span.pl-1 title]]))))))
+                                           {:as-dropdown? true
+                                            :content-props {:onClick #(shui/popup-hide!)}}))})]))

+ 1 - 1
src/main/frontend/handler/events.cljs

@@ -314,7 +314,7 @@
     (if (gdom/getElement popup-id)
       (shui/popup-hide! popup-id)
       (shui/popup-show!
-       (gdom/getElement "dots-menu")
+       (js/document.querySelector ".toolbar-dots-btn")
        (fn []
          (settings/appearance))
        {:id popup-id

+ 4 - 3
src/main/frontend/worker/db/migrate.cljs

@@ -531,9 +531,10 @@
    [47 {:fix replace-hidden-type-with-schema}]
    [48 {:properties [:logseq.property/default-value :logseq.property/scalar-default-value]}]
    [49 {:fix replace-special-id-ref-with-id-ref}]
-   [50 {:classes [:logseq.class/Property :logseq.class/Tag :logseq.class/Page :logseq.class/Whiteboard]}]
-   [51 {:fix replace-block-type-with-tags}]
-   [52 {:properties [:logseq.task/scheduled :logseq.task/recur-frequency :logseq.task/recur-unit :logseq.task/repeated?]
+   [50 {:properties [:logseq.user/name :logseq.user/email :logseq.user/avatar]}]
+   [51 {:classes [:logseq.class/Property :logseq.class/Tag :logseq.class/Page :logseq.class/Whiteboard]}]
+   [52 {:fix replace-block-type-with-tags}]
+   [53 {:properties [:logseq.task/scheduled :logseq.task/recur-frequency :logseq.task/recur-unit :logseq.task/repeated?]
         :fix add-scheduled-to-task}]])
 
 (let [max-schema-version (apply max (map first schema-version->updates))]

+ 1 - 1
src/main/frontend/worker/db_worker.cljs

@@ -778,7 +778,7 @@
   (rtc-get-users-info
    [this token graph-uuid]
    (with-write-transit-str
-     (js/Promise. (rtc-core/new-task--get-user-info token graph-uuid))))
+     (js/Promise. (rtc-core/new-task--get-users-info token graph-uuid))))
 
   (rtc-get-block-content-versions
    [this token graph-uuid block-uuid]

+ 20 - 0
src/main/frontend/worker/rtc/client_op.cljs

@@ -99,6 +99,12 @@
             [:db/add "e" :local-tx t])]
       (d/transact! conn [tx-data]))))
 
+(defn remove-local-tx
+  [repo]
+  (when-let [conn (worker-state/get-client-ops-conn repo)]
+    (when-let [datom (first (d/datoms @conn :avet :local-tx))]
+      (d/transact! conn [[:db/retract (:e datom) :local-tx]]))))
+
 (defn get-local-tx
   [repo]
   (when-let [conn (worker-state/get-client-ops-conn repo)]
@@ -298,6 +304,20 @@
                               update-asset-op (conj [:db.fn/retractAttribute e :update-asset]))))))]
             (d/transact! conn tx-data)))))))
 
+(defn add-all-exists-asset-as-ops
+  [repo]
+  (let [conn (worker-state/get-datascript-conn repo)
+        _ (assert (some? conn))
+        asset-block-uuids (d/q '[:find [?block-uuid ...]
+                                 :where
+                                 [?b :block/uuid ?block-uuid]
+                                 [?b :logseq.property.asset/type]]
+                               @conn)
+        ops (map
+             (fn [block-uuid] [:update-asset 1 {:block-uuid block-uuid}])
+             asset-block-uuids)]
+    (add-asset-ops repo ops)))
+
 (defn- get-all-asset-ops*
   [db]
   (->> (d/datoms db :eavt)

+ 3 - 0
src/main/frontend/worker/rtc/const.cljs

@@ -223,6 +223,9 @@
       ["get-users-info"
        [:map
         [:graph-uuid :uuid]]]
+      ["inject-users-info"
+       [:map
+        [:graph-uuid :uuid]]]
       ["delete-graph"
        [:map
         [:graph-uuid :uuid]]]

+ 54 - 9
src/main/frontend/worker/rtc/core.cljs

@@ -1,6 +1,8 @@
 (ns frontend.worker.rtc.core
   "Main(use missionary) ns for rtc related fns"
-  (:require [frontend.common.missionary-util :as c.m]
+  (:require [clojure.data :as data]
+            [datascript.core :as d]
+            [frontend.common.missionary-util :as c.m]
             [frontend.worker.device :as worker-device]
             [frontend.worker.rtc.asset :as r.asset]
             [frontend.worker.rtc.client :as r.client]
@@ -80,14 +82,43 @@
            (m/?< clock-flow)
            (catch Cancelled _ (m/amb))))))))
 
+(defn create-inject-users-info-flow
+  "Return a flow: emit event if need to notify the server to inject users-info to graph."
+  [repo online-users-updated-flow]
+  (m/ap
+    (if-let [conn (worker-state/get-datascript-conn repo)]
+      (if-let [online-users (seq (m/?> online-users-updated-flow))]
+        (let [user-uuid->user (into {} (map (juxt :user/uuid identity) online-users))
+              user-blocks (keep (fn [user-uuid] (d/entity @conn [:block/uuid user-uuid])) (keys user-uuid->user))]
+          (if (or (not= (count user-blocks) (count user-uuid->user))
+                  (some
+                   ;; check if some attrs not equal among user-blocks and online-users
+                   (fn [user-block]
+                     (let [user (user-uuid->user (:block/uuid user-block))
+                           [diff-r1 diff-r2]
+                           (data/diff
+                            (select-keys user-block [:logseq.user/name :logseq.user/email :logseq.user/avatar])
+                            (update-keys
+                             (select-keys user [:user/name :user/email :user/avatar])
+                             (fn [k] (keyword "logseq.user" (name k)))))]
+                       (or (some? diff-r1) (some? diff-r2))))
+                   user-blocks))
+            (m/amb {:type :inject-users-info}
+                   ;; then trigger a pull-remote-updates to update local-graph
+                   {:type :pull-remote-updates :from :x})
+            (m/amb)))
+        (m/amb))
+      (m/amb))))
+
 (defn- create-mixed-flow
   "Return a flow that emits all kinds of events:
   `:remote-update`: remote-updates data from server
   `:remote-asset-update`: remote asset-updates from server
   `:local-update-check`: event to notify to check if there're some new local-updates, then push to remote.
   `:online-users-updated`: online users info updated
-  `:pull-remote-updates`: pull remote updates"
-  [repo get-ws-create-task *auto-push?]
+  `:pull-remote-updates`: pull remote updates
+  `:inject-users-info`: notify server to inject users-info into the graph"
+  [repo get-ws-create-task *auto-push? *online-users]
   (let [remote-updates-flow (m/eduction
                              (map (fn [data]
                                     (case (:req-id data)
@@ -98,7 +129,8 @@
         local-updates-check-flow (m/eduction
                                   (map (fn [data] {:type :local-update-check :value data}))
                                   (create-local-updates-check-flow repo *auto-push? 2000))
-        mix-flow (m/stream (c.m/mix remote-updates-flow local-updates-check-flow))]
+        inject-user-info-flow (create-inject-users-info-flow repo (m/watch *online-users))
+        mix-flow (c.m/mix remote-updates-flow local-updates-check-flow inject-user-info-flow)]
     (c.m/mix mix-flow (create-pull-remote-updates-flow 60000 mix-flow))))
 
 (defn- create-ws-state-flow
@@ -140,6 +172,7 @@
       (finally
         (reset! *rtc-lock nil)))))
 
+(declare new-task--inject-users-info)
 (defn- create-rtc-loop
   "Return a map with [:rtc-state-flow :rtc-loop-task :*rtc-auto-push? :onstarted-task]
   TODO: auto refresh token if needed"
@@ -160,7 +193,7 @@
                                     get-ws-create-task graph-uuid repo conn *last-calibrate-t *online-users)
         {:keys [assets-sync-loop-task]}
         (r.asset/create-assets-sync-loop repo get-ws-create-task graph-uuid conn *auto-push?)
-        mixed-flow                 (create-mixed-flow repo get-ws-create-task *auto-push?)]
+        mixed-flow                 (create-mixed-flow repo get-ws-create-task *auto-push? *online-users)]
     (assert (some? *current-ws))
     {:rtc-state-flow     (create-rtc-state-flow (create-ws-state-flow *current-ws))
      :*rtc-auto-push?    *auto-push?
@@ -199,7 +232,10 @@
 
                :pull-remote-updates
                (m/? (r.client/new-task--pull-remote-data
-                     repo conn graph-uuid date-formatter get-ws-create-task add-log-fn))))
+                     repo conn graph-uuid date-formatter get-ws-create-task add-log-fn))
+
+               :inject-users-info
+               (m/? (new-task--inject-users-info token graph-uuid))))
            (m/ap)
            (m/reduce {} nil)
            (m/?))
@@ -284,7 +320,7 @@
         (when ex-data (prn ::delete-graph-failed graph-uuid ex-data))
         (boolean (nil? ex-data))))))
 
-(defn new-task--get-user-info
+(defn new-task--get-users-info
   "Return a task that return users-info about the graph."
   [token graph-uuid]
   (let [{:keys [get-ws-create-task]} (gen-get-ws-create-map--memoized (ws-util/get-ws-url token))]
@@ -292,6 +328,12 @@
             (ws-util/send&recv get-ws-create-task
                                {:action "get-users-info" :graph-uuid graph-uuid}))))
 
+(defn new-task--inject-users-info
+  [token graph-uuid]
+  (let [{:keys [get-ws-create-task]} (gen-get-ws-create-map--memoized (ws-util/get-ws-url token))]
+    (ws-util/send&recv get-ws-create-task
+                       {:action "inject-users-info" :graph-uuid graph-uuid})))
+
 (defn new-task--grant-access-to-others
   [token graph-uuid & {:keys [target-user-uuids target-user-emails]}]
   (let [{:keys [get-ws-create-task]} (gen-get-ws-create-map--memoized (ws-util/get-ws-url token))]
@@ -393,7 +435,6 @@
   (fn [_ v] (worker-util/post-message :rtc-sync-state v))
   create-get-state-flow))
 
-
 (comment
   (do
     (def user-uuid "7f41990d-2c8f-4f79-b231-88e9f652e072")
@@ -426,4 +467,8 @@
     ((->> (m/sample vector
                     (m/latest identity (m/reductions {} 0  (sleep-emit [1000 1 2])))
                     (sleep-emit [2000 3000 1000]))
-          (m/reduce (fn [_ v] (prn :v v)))) prn prn)))
+          (m/reduce (fn [_ v] (prn :v v)))) prn prn))
+
+  (let [f (m/stream (m/ap (m/amb 1 2 3 4)))]
+    ((m/reduce (fn [r v] (conj r v)) (m/reductions {} :xxx f)) prn prn)
+    ((m/reduce (fn [r v] (conj r v)) f) prn prn)))

+ 2 - 0
src/main/frontend/worker/rtc/full_upload_download_graph.cljs

@@ -141,6 +141,8 @@
                            [{:db/ident :logseq.kv/graph-uuid :kv/value graph-uuid}
                             {:db/ident :logseq.kv/graph-local-tx :kv/value "0"}])
             (client-op/update-graph-uuid repo graph-uuid)
+            (client-op/remove-local-tx repo)
+            (client-op/add-all-exists-asset-as-ops repo)
             (crypt/store-graph-keys-jwk repo aes-key-jwk)
             (when-not rtc-const/RTC-E2E-TEST
               (let [^js worker-obj (:worker/object @worker-state/*state)]

+ 1 - 1
src/test/frontend/worker/rtc/rtc_fns_test.cljs

@@ -17,7 +17,7 @@
   test-helper/db-based-start-and-destroy-db
   (worker-fixtures/listen-test-db-fixture [:sync-db-to-main-thread]))
 
-(deftest update-remote-data-by-local-unpushed-ops-test
+(deftest ^:large-vars/cleanup-todo update-remote-data-by-local-unpushed-ops-test
   (testing "case1"
     (let [[uuid1 uuid2] (repeatedly (comp str random-uuid))
           affected-blocks-map

File diff suppressed because it is too large
+ 218 - 381
static/yarn.lock


+ 11 - 9
yarn.lock

@@ -1089,10 +1089,12 @@
   dependencies:
     undici-types "~6.19.2"
 
-"@types/node@^18.11.18":
-  version "18.17.19"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.19.tgz#80c9b8a89d3648d9e6098f4a7184e03833fee3c5"
-  integrity sha512-+pMhShR3Or5GR0/sp4Da7FnhVmTalWm81M6MkEldbwjETSaPalw138Z4KdpQaistvqQxLB7Cy4xwYdxpbSOs9Q==
+"@types/node@^20.9.0":
+  version "20.17.10"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.10.tgz#3f7166190aece19a0d1d364d75c8b0b5778c1e18"
+  integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==
+  dependencies:
+    undici-types "~6.19.2"
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.2"
@@ -2902,13 +2904,13 @@ electron-to-chromium@^1.4.526:
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz#7c900fd73d9d2e8bb0dab0e301f25f0f4776ef2c"
   integrity sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==
 
-electron@28.3.1:
-  version "28.3.1"
-  resolved "https://registry.yarnpkg.com/electron/-/electron-28.3.1.tgz#babb3ff8e246336e9cd1c1966f16a55ba723ea06"
-  integrity sha512-aF9fONuhVDJlctJS7YOw76ynxVAQdfIWmlhRMKits24tDcdSL0eMHUS0wWYiRfGWbQnUKB6V49Rf17o32f4/fg==
+electron@31.7.5:
+  version "31.7.5"
+  resolved "https://registry.yarnpkg.com/electron/-/electron-31.7.5.tgz#98396c75041808b26c7b6a8844cbedacee93d8a6"
+  integrity sha512-8zFzVJdhxTRmoPcRiKkEmPW0bJHAUsTQJwEX2YJ8X0BVFIJLwSvHkSlpCjEExVbNCAk+gHnkIYX+2OyCXrRwHQ==
   dependencies:
     "@electron/get" "^2.0.0"
-    "@types/node" "^18.11.18"
+    "@types/node" "^20.9.0"
     extract-zip "^2.0.1"
 
 element-resize-detector@^1.1.14:

Some files were not shown because too many files changed in this diff