mirror of
https://github.com/logseq/logseq.git
synced 2026-05-28 14:39:48 +00:00
Merge branch 'feat/db' into fix/multiple-tabs
This commit is contained in:
@@ -182,6 +182,7 @@
|
||||
logseq.db.file-based.entity-util file-entity-util
|
||||
logseq.db.frontend.class db-class
|
||||
logseq.db.frontend.content db-content
|
||||
logseq.db.frontend.db db-db
|
||||
logseq.db.frontend.db-ident db-ident
|
||||
logseq.db.frontend.entity-plus entity-plus
|
||||
logseq.db.frontend.entity-util entity-util
|
||||
|
||||
2
deps.edn
2
deps.edn
@@ -40,7 +40,7 @@
|
||||
logseq/shui {:local/root "deps/shui"}
|
||||
metosin/malli {:mvn/version "0.16.1"}
|
||||
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
||||
missionary/missionary {:mvn/version "b.39"}
|
||||
missionary/missionary {:mvn/version "b.44"}
|
||||
meander/epsilon {:mvn/version "0.0.650"}
|
||||
|
||||
io.github.open-spaced-repetition/cljc-fsrs {:git/sha "0e70e96a73cf63c85dcc2df4d022edf12806b239"
|
||||
|
||||
1
deps/db/.clj-kondo/config.edn
vendored
1
deps/db/.clj-kondo/config.edn
vendored
@@ -16,6 +16,7 @@
|
||||
logseq.db.common.view db-view
|
||||
logseq.db.frontend.content db-content
|
||||
logseq.db.frontend.class db-class
|
||||
logseq.db.frontend.db db-db
|
||||
logseq.db.frontend.db-ident db-ident
|
||||
logseq.db.frontend.inputs db-inputs
|
||||
logseq.db.frontend.property db-property
|
||||
|
||||
130
deps/db/src/logseq/db.cljs
vendored
130
deps/db/src/logseq/db.cljs
vendored
@@ -1,19 +1,19 @@
|
||||
(ns logseq.db
|
||||
"Main namespace for public db fns. For DB and file graphs.
|
||||
For shared file graph only fns, use logseq.graph-parser.db"
|
||||
"Main namespace for db fns that handles DB and file graphs. For db graph only
|
||||
fns, use logseq.db.frontend.db and for file graph only fns, use
|
||||
logseq.graph-parser.db"
|
||||
(:require [clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[clojure.walk :as walk]
|
||||
[datascript.core :as d]
|
||||
[datascript.impl.entity :as de]
|
||||
[logseq.common.util :as common-util]
|
||||
[logseq.common.util.namespace :as ns-util]
|
||||
[logseq.common.util.page-ref :as page-ref]
|
||||
[logseq.common.uuid :as common-uuid]
|
||||
[logseq.db.common.delete-blocks :as delete-blocks] ;; Load entity extensions
|
||||
[logseq.db.common.entity-util :as common-entity-util]
|
||||
[logseq.db.common.sqlite :as sqlite-common-db]
|
||||
[logseq.db.frontend.class :as db-class]
|
||||
[logseq.db.frontend.db :as db-db]
|
||||
[logseq.db.frontend.entity-plus :as entity-plus]
|
||||
[logseq.db.frontend.entity-util :as entity-util]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
@@ -412,11 +412,6 @@
|
||||
[]
|
||||
(common-uuid/gen-uuid))
|
||||
|
||||
(defn get-classes-with-property
|
||||
"Get classes which have given property as a class property"
|
||||
[db property-id]
|
||||
(:logseq.property.class/_properties (d/entity db property-id)))
|
||||
|
||||
(defn get-alias-source-page
|
||||
"return the source page (page-name) of an alias"
|
||||
[db alias-id]
|
||||
@@ -492,37 +487,13 @@
|
||||
e))))))
|
||||
|
||||
(def built-in? entity-util/built-in?)
|
||||
|
||||
(defn built-in-class-property?
|
||||
"Whether property a built-in property for the specific class"
|
||||
[class-entity property-entity]
|
||||
(and (built-in? class-entity)
|
||||
(class? class-entity)
|
||||
(built-in? property-entity)
|
||||
(contains? (set (get-in (db-class/built-in-classes (:db/ident class-entity)) [:schema :properties]))
|
||||
(:db/ident property-entity))))
|
||||
|
||||
(defn private-built-in-page?
|
||||
"Private built-in pages should not be navigable or searchable by users. Later it
|
||||
could be useful to use this for the All Pages view"
|
||||
[page]
|
||||
(cond (property? page)
|
||||
(not (public-built-in-property? page))
|
||||
(or (class? page) (internal-page? page))
|
||||
false
|
||||
;; Default to true for closed value and future internal types.
|
||||
;; Other types like whiteboard are not considered because they aren't built-in
|
||||
:else
|
||||
true))
|
||||
(def get-classes-with-property db-db/get-classes-with-property)
|
||||
(def built-in-class-property? db-db/built-in-class-property?)
|
||||
(def private-built-in-page? db-db/private-built-in-page?)
|
||||
|
||||
(def write-transit-str sqlite-util/write-transit-str)
|
||||
(def read-transit-str sqlite-util/read-transit-str)
|
||||
|
||||
(defn build-favorite-tx
|
||||
"Builds tx for a favorite block in favorite page"
|
||||
[favorite-uuid]
|
||||
{:block/link [:block/uuid favorite-uuid]
|
||||
:block/title ""})
|
||||
(def build-favorite-tx db-db/build-favorite-tx)
|
||||
|
||||
(defn get-key-value
|
||||
[db key-ident]
|
||||
@@ -544,87 +515,20 @@
|
||||
[db]
|
||||
(when db (get-key-value db :logseq.kv/remote-schema-version)))
|
||||
|
||||
(defn get-all-properties
|
||||
[db]
|
||||
(->> (d/datoms db :avet :block/tags :logseq.class/Property)
|
||||
(map (fn [d]
|
||||
(d/entity db (:e d))))))
|
||||
|
||||
(defn get-page-parents
|
||||
[node & {:keys [node-class?]}]
|
||||
(when-let [parent (:logseq.property/parent node)]
|
||||
(loop [current-parent parent
|
||||
parents' []]
|
||||
(if (and
|
||||
current-parent
|
||||
(if node-class? (class? current-parent) true)
|
||||
(not (contains? parents' current-parent)))
|
||||
(recur (:logseq.property/parent current-parent)
|
||||
(conj parents' current-parent))
|
||||
(vec (reverse parents'))))))
|
||||
|
||||
(defn get-title-with-parents
|
||||
[entity]
|
||||
(if (or (entity-util/class? entity) (entity-util/internal-page? entity))
|
||||
(let [parents' (->> (get-page-parents entity)
|
||||
(remove (fn [e] (= :logseq.class/Root (:db/ident e))))
|
||||
vec)]
|
||||
(string/join
|
||||
ns-util/parent-char
|
||||
(map :block/title (conj (vec parents') entity))))
|
||||
(:block/title entity)))
|
||||
|
||||
(defn get-classes-parents
|
||||
[tags]
|
||||
(let [tags' (filter class? tags)
|
||||
result (mapcat #(get-page-parents % {:node-class? true}) tags')]
|
||||
(set result)))
|
||||
|
||||
(defn class-instance?
|
||||
"Whether `object` is an instance of `class`"
|
||||
[class object]
|
||||
(let [tags (:block/tags object)
|
||||
tags-ids (set (map :db/id tags))]
|
||||
(or
|
||||
(contains? tags-ids (:db/id class))
|
||||
(let [class-parent-ids (set (map :db/id (get-classes-parents tags)))]
|
||||
(contains? (set/union class-parent-ids tags-ids) (:db/id class))))))
|
||||
|
||||
(defn inline-tag?
|
||||
[block-raw-title tag]
|
||||
(assert (string? block-raw-title) "block-raw-title should be a string")
|
||||
(string/includes? block-raw-title (str "#" (page-ref/->page-ref (:block/uuid tag)))))
|
||||
|
||||
(defonce node-display-type-classes
|
||||
#{:logseq.class/Code-block :logseq.class/Math-block :logseq.class/Quote-block})
|
||||
|
||||
(defn get-class-ident-by-display-type
|
||||
[display-type]
|
||||
(case display-type
|
||||
:code :logseq.class/Code-block
|
||||
:math :logseq.class/Math-block
|
||||
:quote :logseq.class/Quote-block
|
||||
nil))
|
||||
|
||||
(defn get-display-type-by-class-ident
|
||||
[class-ident]
|
||||
(case class-ident
|
||||
:logseq.class/Code-block :code
|
||||
:logseq.class/Math-block :math
|
||||
:logseq.class/Quote-block :quote
|
||||
nil))
|
||||
(def get-all-properties db-db/get-all-properties)
|
||||
(def get-page-parents db-db/get-page-parents)
|
||||
(def get-classes-parents db-db/get-classes-parents)
|
||||
(def get-title-with-parents db-db/get-title-with-parents)
|
||||
(def class-instance? db-db/class-instance?)
|
||||
(def inline-tag? db-db/inline-tag?)
|
||||
(def node-display-type-classes db-db/node-display-type-classes)
|
||||
(def get-class-ident-by-display-type db-db/get-class-ident-by-display-type)
|
||||
(def get-display-type-by-class-ident db-db/get-display-type-by-class-ident)
|
||||
|
||||
(def get-recent-updated-pages sqlite-common-db/get-recent-updated-pages)
|
||||
|
||||
(def get-latest-journals sqlite-common-db/get-latest-journals)
|
||||
|
||||
(defn get-all-namespace-relation
|
||||
[db]
|
||||
(d/q '[:find ?page ?parent
|
||||
:where
|
||||
[?page :block/namespace ?parent]]
|
||||
db))
|
||||
|
||||
(defn get-pages-relation
|
||||
[db with-journal?]
|
||||
(if (entity-plus/db-based-graph? db)
|
||||
|
||||
10
deps/db/src/logseq/db/common/view.cljs
vendored
10
deps/db/src/logseq/db/common/view.cljs
vendored
@@ -311,6 +311,7 @@
|
||||
(= (:db/id block) id)
|
||||
(= id (:db/id (:block/page block)))
|
||||
(ldb/hidden? (:block/page block))
|
||||
(ldb/hidden? block)
|
||||
(contains? (set (map :db/id (:block/tags block))) (:db/id entity))
|
||||
(some? (get block (:db/ident entity))))
|
||||
(or
|
||||
@@ -331,7 +332,8 @@
|
||||
distinct))
|
||||
full-ref-blocks)
|
||||
(remove nil?)
|
||||
(frequencies))]
|
||||
(frequencies)
|
||||
(sort-by second #(> %1 %2)))]
|
||||
{:ref-pages-count ref-pages-count
|
||||
:ref-blocks ref-blocks}))
|
||||
|
||||
@@ -564,9 +566,11 @@
|
||||
[(:block/uuid (first blocks))
|
||||
(map (fn [b]
|
||||
{:db/id (:db/id b)
|
||||
:block/parent (:block/uuid (:block/parent b))}) blocks)])
|
||||
:block/parent (:block/uuid (:block/parent b))})
|
||||
(ldb/sort-by-order blocks))])
|
||||
parent-groups))
|
||||
(map :db/id entities))]
|
||||
(->> (sort-entities db sorting entities)
|
||||
(map :db/id)))]
|
||||
[by-value' group]))
|
||||
result)
|
||||
(map :db/id result))]
|
||||
|
||||
113
deps/db/src/logseq/db/frontend/db.cljs
vendored
Normal file
113
deps/db/src/logseq/db/frontend/db.cljs
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
(ns logseq.db.frontend.db
|
||||
"DB graph fns commonly used outside db dep"
|
||||
(:require [clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[datascript.core :as d]
|
||||
[logseq.common.util.namespace :as ns-util]
|
||||
[logseq.common.util.page-ref :as page-ref]
|
||||
[logseq.db.frontend.class :as db-class]
|
||||
[logseq.db.frontend.entity-util :as entity-util]
|
||||
[logseq.db.frontend.property :as db-property]))
|
||||
|
||||
(defn get-classes-with-property
|
||||
"Get classes which have given property as a class property"
|
||||
[db property-id]
|
||||
(:logseq.property.class/_properties (d/entity db property-id)))
|
||||
|
||||
(defn built-in-class-property?
|
||||
"Whether property a built-in property for the specific class"
|
||||
[class-entity property-entity]
|
||||
(and (entity-util/built-in? class-entity)
|
||||
(entity-util/class? class-entity)
|
||||
(entity-util/built-in? property-entity)
|
||||
(contains? (set (get-in (db-class/built-in-classes (:db/ident class-entity)) [:schema :properties]))
|
||||
(:db/ident property-entity))))
|
||||
|
||||
(defn private-built-in-page?
|
||||
"Private built-in pages should not be navigable or searchable by users. Later it
|
||||
could be useful to use this for the All Pages view"
|
||||
[page]
|
||||
(cond (entity-util/property? page)
|
||||
(not (db-property/public-built-in-property? page))
|
||||
(or (entity-util/class? page) (entity-util/internal-page? page))
|
||||
false
|
||||
;; Default to true for closed value and future internal types.
|
||||
;; Other types like whiteboard are not considered because they aren't built-in
|
||||
:else
|
||||
true))
|
||||
|
||||
(defn build-favorite-tx
|
||||
"Builds tx for a favorite block in favorite page"
|
||||
[favorite-uuid]
|
||||
{:block/link [:block/uuid favorite-uuid]
|
||||
:block/title ""})
|
||||
|
||||
(defn get-all-properties
|
||||
[db]
|
||||
(->> (d/datoms db :avet :block/tags :logseq.class/Property)
|
||||
(map (fn [d]
|
||||
(d/entity db (:e d))))))
|
||||
|
||||
(defn get-page-parents
|
||||
[node & {:keys [node-class?]}]
|
||||
(when-let [parent (:logseq.property/parent node)]
|
||||
(loop [current-parent parent
|
||||
parents' []]
|
||||
(if (and
|
||||
current-parent
|
||||
(if node-class? (entity-util/class? current-parent) true)
|
||||
(not (contains? parents' current-parent)))
|
||||
(recur (:logseq.property/parent current-parent)
|
||||
(conj parents' current-parent))
|
||||
(vec (reverse parents'))))))
|
||||
|
||||
(defn get-title-with-parents
|
||||
[entity]
|
||||
(if (or (entity-util/class? entity) (entity-util/internal-page? entity))
|
||||
(let [parents' (->> (get-page-parents entity)
|
||||
(remove (fn [e] (= :logseq.class/Root (:db/ident e))))
|
||||
vec)]
|
||||
(string/join
|
||||
ns-util/parent-char
|
||||
(map :block/title (conj (vec parents') entity))))
|
||||
(:block/title entity)))
|
||||
|
||||
(defn get-classes-parents
|
||||
[tags]
|
||||
(let [tags' (filter entity-util/class? tags)
|
||||
result (mapcat #(get-page-parents % {:node-class? true}) tags')]
|
||||
(set result)))
|
||||
|
||||
(defn class-instance?
|
||||
"Whether `object` is an instance of `class`"
|
||||
[class object]
|
||||
(let [tags (:block/tags object)
|
||||
tags-ids (set (map :db/id tags))]
|
||||
(or
|
||||
(contains? tags-ids (:db/id class))
|
||||
(let [class-parent-ids (set (map :db/id (get-classes-parents tags)))]
|
||||
(contains? (set/union class-parent-ids tags-ids) (:db/id class))))))
|
||||
|
||||
(defn inline-tag?
|
||||
[block-raw-title tag]
|
||||
(assert (string? block-raw-title) "block-raw-title should be a string")
|
||||
(string/includes? block-raw-title (str "#" (page-ref/->page-ref (:block/uuid tag)))))
|
||||
|
||||
(defonce node-display-type-classes
|
||||
#{:logseq.class/Code-block :logseq.class/Math-block :logseq.class/Quote-block})
|
||||
|
||||
(defn get-class-ident-by-display-type
|
||||
[display-type]
|
||||
(case display-type
|
||||
:code :logseq.class/Code-block
|
||||
:math :logseq.class/Math-block
|
||||
:quote :logseq.class/Quote-block
|
||||
nil))
|
||||
|
||||
(defn get-display-type-by-class-ident
|
||||
[class-ident]
|
||||
(case class-ident
|
||||
:logseq.class/Code-block :code
|
||||
:logseq.class/Math-block :math
|
||||
:logseq.class/Quote-block :quote
|
||||
nil))
|
||||
6
deps/db/src/logseq/db/sqlite/build.cljs
vendored
6
deps/db/src/logseq/db/sqlite/build.cljs
vendored
@@ -659,8 +659,10 @@
|
||||
(if (:logseq.property/classes m)
|
||||
(update m :logseq.property/classes
|
||||
(fn [cs]
|
||||
(mapv #(or (some->> (:db/ident %) class-ident->id (hash-map :db/id))
|
||||
(throw (ex-info (str "No :db/id found for :db/ident " (pr-str (:db/ident %))) {})))
|
||||
(mapv #(if (db-class/logseq-class? (:db/ident %))
|
||||
%
|
||||
(or (some->> (:db/ident %) class-ident->id (hash-map :db/id))
|
||||
(throw (ex-info (str "No :db/id found for :db/ident " (pr-str %)) {}))))
|
||||
cs)))
|
||||
m))
|
||||
properties-tx)
|
||||
|
||||
55
deps/db/src/logseq/db/sqlite/export.cljs
vendored
55
deps/db/src/logseq/db/sqlite/export.cljs
vendored
@@ -9,11 +9,13 @@
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.class :as db-class]
|
||||
[logseq.db.frontend.content :as db-content]
|
||||
[logseq.db.frontend.db :as db-db]
|
||||
[logseq.db.frontend.entity-plus :as entity-plus]
|
||||
[logseq.db.frontend.entity-util :as entity-util]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
[logseq.db.sqlite.build :as sqlite-build]
|
||||
[medley.core :as medley]))
|
||||
[medley.core :as medley]
|
||||
[logseq.db.frontend.property.type :as db-property-type]))
|
||||
|
||||
;; Export fns
|
||||
;; ==========
|
||||
@@ -40,7 +42,7 @@
|
||||
|
||||
(defn- build-pvalue-entity-for-build-page
|
||||
[pvalue]
|
||||
(cond (ldb/internal-page? pvalue)
|
||||
(cond (entity-util/internal-page? pvalue)
|
||||
;; Should page properties be pulled here?
|
||||
[:build/page (cond-> (shallow-copy-page pvalue)
|
||||
(seq (:block/tags pvalue))
|
||||
@@ -48,7 +50,10 @@
|
||||
(entity-util/journal? pvalue)
|
||||
[:build/page {:build/journal (:block/journal-day pvalue)}]))
|
||||
|
||||
(defn- build-pvalue-entity-default [ent-properties pvalue options]
|
||||
(defn- build-pvalue-entity-default [db ent-properties pvalue
|
||||
{:keys [include-uuid-fn]
|
||||
:or {include-uuid-fn (constantly false)}
|
||||
:as options}]
|
||||
(if (or (seq ent-properties) (seq (:block/tags pvalue)))
|
||||
(cond-> {:build/property-value :block
|
||||
:block/title (or (block-title pvalue)
|
||||
@@ -57,7 +62,17 @@
|
||||
(assoc :build/tags (->build-tags (:block/tags pvalue)))
|
||||
|
||||
(seq ent-properties)
|
||||
(assoc :build/properties ent-properties)
|
||||
(assoc :build/properties
|
||||
;; TODO: Add support for ref properties here and in sqlite.build
|
||||
(->> ent-properties
|
||||
(keep (fn [[k v]]
|
||||
(let [prop-type (:logseq.property/type (d/entity db k))]
|
||||
(when-not (contains? db-property-type/all-ref-property-types prop-type)
|
||||
[k v]))))
|
||||
(into {})))
|
||||
|
||||
(include-uuid-fn (:block/uuid pvalue))
|
||||
(assoc :block/uuid (:block/uuid pvalue) :build/keep-uuid? true)
|
||||
|
||||
(:include-timestamps? options)
|
||||
(merge (select-keys pvalue [:block/created-at :block/updated-at])))
|
||||
@@ -87,7 +102,7 @@
|
||||
(medley/filter-keys db-property/internal-property?))
|
||||
ent-properties (when (and (not (:block/closed-value-property pvalue)) (seq ent-properties*))
|
||||
(buildable-properties db' ent-properties* properties-config' options'))]
|
||||
(build-pvalue-entity-default ent-properties pvalue options'))))))]
|
||||
(build-pvalue-entity-default db ent-properties pvalue options'))))))]
|
||||
(->> ent-properties
|
||||
(map (fn [[k v]]
|
||||
[k
|
||||
@@ -259,7 +274,8 @@
|
||||
(mapcat (fn [val-or-vals]
|
||||
(keep #(when (and (vector? %)
|
||||
(= :block/uuid (first %))
|
||||
(::existing-property-value? (meta %))) (second %))
|
||||
(::existing-property-value? (meta %)))
|
||||
(second %))
|
||||
(if (set? val-or-vals) val-or-vals [val-or-vals]))))
|
||||
set))
|
||||
|
||||
@@ -293,7 +309,7 @@
|
||||
(when-let [prop-ids (seq (map :db/ident (filter entity-util/property? ents)))]
|
||||
(build-export-properties db prop-ids export-opts))
|
||||
classes
|
||||
(when-let [class-ents (seq (filter ldb/class? ents))]
|
||||
(when-let [class-ents (seq (filter entity-util/class? ents))]
|
||||
(->> class-ents
|
||||
(map #(vector (:db/ident %) (build-export-class % export-opts)))
|
||||
(into {})))]
|
||||
@@ -328,7 +344,7 @@
|
||||
(let [class-parent-ents (->> classes-config
|
||||
(filter #(:build/class-parent (val %)))
|
||||
(map #(d/entity db (key %)))
|
||||
ldb/get-classes-parents)
|
||||
db-db/get-classes-parents)
|
||||
classes
|
||||
(->> class-parent-ents
|
||||
(remove #(db-class/logseq-class? (:db/ident %)))
|
||||
@@ -670,8 +686,16 @@
|
||||
(update :pages-and-blocks
|
||||
(fn [pages-and-blocks]
|
||||
(mapv (fn [{:keys [page blocks]}]
|
||||
{:page (remove-uuid-if-not-ref page)
|
||||
:blocks (sqlite-build/update-each-block blocks remove-uuid-if-not-ref)})
|
||||
(let [page-map {:page (remove-uuid-if-not-ref page)
|
||||
:blocks (sqlite-build/update-each-block blocks remove-uuid-if-not-ref)}
|
||||
;; TODO: Walk data structure via :build/properties instead of slower walk
|
||||
page-map'
|
||||
(walk/postwalk (fn [f]
|
||||
(if (and (map? f) (:build/property-value f))
|
||||
(remove-uuid-if-not-ref f)
|
||||
f))
|
||||
page-map)]
|
||||
page-map'))
|
||||
pages-and-blocks))))))
|
||||
|
||||
(defn- add-ontology-for-include-namespaces
|
||||
@@ -750,12 +774,19 @@
|
||||
undefined))
|
||||
|
||||
(defn- find-undefined-uuids [{:keys [classes properties pages-and-blocks]}]
|
||||
(let [known-uuids
|
||||
(let [pvalue-known-uuids (atom #{})
|
||||
_ (walk/postwalk (fn [f]
|
||||
(if (and (map? f) (:build/property-value f) (:block/uuid f))
|
||||
(swap! pvalue-known-uuids conj (:block/uuid f))
|
||||
f))
|
||||
pages-and-blocks)
|
||||
known-uuids
|
||||
(->> (concat (keep :block/uuid (vals classes))
|
||||
(keep :block/uuid (vals properties))
|
||||
(keep #(get-in % [:page :block/uuid]) pages-and-blocks)
|
||||
(mapcat #(sqlite-build/extract-from-blocks (:blocks %) (fn [m] (some-> m :block/uuid vector)))
|
||||
pages-and-blocks))
|
||||
pages-and-blocks)
|
||||
@pvalue-known-uuids)
|
||||
set)
|
||||
;; Only looks one-level deep in properties e.g. not inside :build/page
|
||||
;; Doesn't find :block/link refs
|
||||
|
||||
7
deps/db/src/logseq/db/sqlite/util.cljs
vendored
7
deps/db/src/logseq/db/sqlite/util.cljs
vendored
@@ -52,12 +52,7 @@
|
||||
(merge read-handlers))
|
||||
reader (transit/reader :json {:handlers read-handlers*})]
|
||||
(fn read-transit-str* [s]
|
||||
;; TODO: delete the following pred later
|
||||
;; https://github.com/logseq/logseq/pull/11790#discussion_r2014120469
|
||||
(if (and (string? s) (identical? "[" (first s)))
|
||||
(transit/read reader s)
|
||||
(do (prn :invalid-transit-string s)
|
||||
s)))))
|
||||
(transit/read reader s))))
|
||||
|
||||
(defn db-based-graph?
|
||||
[graph-name]
|
||||
|
||||
@@ -59,3 +59,10 @@
|
||||
[db page-name]
|
||||
(some-> (ldb/get-page db page-name)
|
||||
:block/file))
|
||||
|
||||
(defn get-all-namespace-relation
|
||||
[db]
|
||||
(d/q '[:find ?page ?parent
|
||||
:where
|
||||
[?page :block/namespace ?parent]]
|
||||
db))
|
||||
|
||||
21
deps/outliner/src/logseq/outliner/core.cljs
vendored
21
deps/outliner/src/logseq/outliner/core.cljs
vendored
@@ -221,7 +221,7 @@
|
||||
|
||||
(extend-type Entity
|
||||
otree/INode
|
||||
(-save [this *txs-state db repo _date-formatter {:keys [retract-attributes? retract-attributes]
|
||||
(-save [this *txs-state db repo _date-formatter {:keys [retract-attributes? retract-attributes outliner-op]
|
||||
:or {retract-attributes? true}}]
|
||||
(assert (ds/outliner-txs-state? *txs-state)
|
||||
"db should be satisfied outliner-tx-state?")
|
||||
@@ -233,12 +233,16 @@
|
||||
data)
|
||||
db-based?
|
||||
(dissoc :block/properties))
|
||||
m* (-> data'
|
||||
(dissoc :block/children :block/meta :block/unordered
|
||||
:block.temp/ast-title :block.temp/ast-body :block/level :block.temp/fully-loaded?)
|
||||
common-util/remove-nils
|
||||
block-with-updated-at
|
||||
(fix-tag-ids db {:db-graph? db-based?}))
|
||||
collapse-or-expand? (= outliner-op :collapse-expand-blocks)
|
||||
m* (cond->
|
||||
(-> data'
|
||||
(dissoc :block/children :block/meta :block/unordered
|
||||
:block.temp/ast-title :block.temp/ast-body :block/level :block.temp/fully-loaded?)
|
||||
common-util/remove-nils
|
||||
|
||||
(fix-tag-ids db {:db-graph? db-based?}))
|
||||
(not collapse-or-expand?)
|
||||
block-with-updated-at)
|
||||
db-id (:db/id this)
|
||||
block-uuid (:block/uuid this)
|
||||
eid (or db-id (when block-uuid [:block/uuid block-uuid]))
|
||||
@@ -292,7 +296,8 @@
|
||||
retract-attributes)))))))
|
||||
|
||||
;; Update block's page attributes
|
||||
(update-page-when-save-block *txs-state block-entity m)
|
||||
(when-not collapse-or-expand?
|
||||
(update-page-when-save-block *txs-state block-entity m))
|
||||
;; Remove orphaned refs from block
|
||||
(when (and (:block/title m) (not= (:block/title m) (:block/title block-entity)))
|
||||
(remove-orphaned-refs-when-save db *txs-state block-entity m {:db-graph? db-based?})))
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
(let [dark? (= "dark" theme)
|
||||
relation (ldb/get-pages-relation db journal?)
|
||||
tagged-pages (ldb/get-all-tagged-pages db)
|
||||
namespaces (ldb/get-all-namespace-relation db)
|
||||
namespaces (gp-db/get-all-namespace-relation db)
|
||||
tags (set (map second tagged-pages))
|
||||
full-pages (ldb/get-all-pages db)
|
||||
db-based? (entity-plus/db-based-graph? db)
|
||||
@@ -178,7 +178,7 @@
|
||||
tags (set (remove #(= page-id %) tags))
|
||||
ref-pages (get-page-referenced-pages db page-id)
|
||||
mentioned-pages (get-pages-that-mentioned-page db page-id show-journal)
|
||||
namespaces (ldb/get-all-namespace-relation db)
|
||||
namespaces (gp-db/get-all-namespace-relation db)
|
||||
links (concat
|
||||
namespaces
|
||||
(map (fn [ref-page]
|
||||
@@ -216,7 +216,7 @@
|
||||
(if (ldb/page? b) b (:block/page b))))
|
||||
(remove (fn [node] (= (:db/id block) (:db/id node))))
|
||||
(common-util/distinct-by :db/id))
|
||||
namespaces (ldb/get-all-namespace-relation db)
|
||||
namespaces (gp-db/get-all-namespace-relation db)
|
||||
links (->> (concat
|
||||
namespaces
|
||||
(map (fn [p] [(:db/id block) (:db/id p)]) ref-blocks))
|
||||
|
||||
@@ -21,32 +21,55 @@
|
||||
(m/reductions {} init-value)
|
||||
(m/latest identity))))
|
||||
|
||||
(def delays (reductions * 1000 (repeat 2)))
|
||||
|
||||
(def ^:private retry-sentinel (js-obj))
|
||||
(defn backoff
|
||||
"Retry task when it throw exception `(get ex-data :missionary/retry)`"
|
||||
[delays-seq task]
|
||||
(m/sp
|
||||
(loop [[delay & rest-delays] (seq delays-seq)]
|
||||
(let [r (try
|
||||
(m/? task)
|
||||
(catch :default e
|
||||
(if (and (some-> e ex-data :missionary/retry)
|
||||
(pos-int? delay))
|
||||
(do (m/? (m/sleep delay))
|
||||
(println :missionary/retry "after" delay "ms (" (ex-message e) ")")
|
||||
retry-sentinel)
|
||||
(throw e))))]
|
||||
(if (identical? r retry-sentinel)
|
||||
(recur rest-delays)
|
||||
r)))))
|
||||
|
||||
(defn mix
|
||||
"Return a flow which is mixed by `flows`"
|
||||
[& flows]
|
||||
(m/ap (m/?> (m/?> (count flows) (m/seed flows)))))
|
||||
|
||||
(def never-flow (m/ap (m/? m/never)))
|
||||
|
||||
(def delays (reductions * 1000 (repeat 2)))
|
||||
|
||||
(def ^:private retry-sentinel (js-obj))
|
||||
(defn backoff
|
||||
"Retry task when it throw exception `(get ex-data :missionary/retry)`
|
||||
:delay-seq - retry delay-msecs
|
||||
:reset-flow - retry immediately when getting value from flow and reset delays to init state"
|
||||
[{:keys [delay-seq reset-flow]
|
||||
:or {delay-seq (take 4 delays)
|
||||
reset-flow never-flow}}
|
||||
task]
|
||||
(let [reset-flow* (mix reset-flow never-flow)]
|
||||
(m/sp
|
||||
(loop [[delay & rest-delays] (seq delay-seq)]
|
||||
(let [r (try
|
||||
(m/? task)
|
||||
(catch :default e
|
||||
(if (and (some-> e ex-data :missionary/retry)
|
||||
(pos-int? delay))
|
||||
(let [delay-or-reset
|
||||
(m/? (m/race (m/sleep delay :delay)
|
||||
(m/reduce (fn [_ r] (when r (reduced :reset))) nil
|
||||
(->> (continue-flow reset-flow*)
|
||||
(m/eduction (drop 1) (take 1))))))
|
||||
rest-delays*
|
||||
(case delay-or-reset
|
||||
:delay
|
||||
(do (println :missionary/retry "after" delay "ms (" (ex-message e) ")")
|
||||
rest-delays)
|
||||
:reset
|
||||
(do (println :missionary/retry "retry now (" (ex-message e) ")")
|
||||
delay-seq))]
|
||||
[retry-sentinel rest-delays*])
|
||||
(throw e))))]
|
||||
(if (and (vector? r)
|
||||
(first r) ;; if delete this `(first r)`,
|
||||
;; the code continues to the next line even if r=0...
|
||||
;; I suspect it's a bug in missionary.
|
||||
(identical? retry-sentinel (first r)))
|
||||
(recur (second r))
|
||||
r))))))
|
||||
|
||||
(defn clock
|
||||
"Return a flow that emits `value` every `interval-ms`."
|
||||
([interval-ms]
|
||||
|
||||
@@ -1082,3 +1082,9 @@ html.is-mac {
|
||||
aspect-ratio: 16 / 9;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.ls-filters {
|
||||
div[data-testid='virtuoso-item-list'] button {
|
||||
@apply mb-2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1270,15 +1270,17 @@
|
||||
type (:logseq.property/type property)
|
||||
multiple-values? (db-property/many? property)
|
||||
v (let [v (get block (:db/ident property))]
|
||||
(cond
|
||||
(and multiple-values? (or (set? v) (and (coll? v) (empty? v)) (nil? v)))
|
||||
v
|
||||
multiple-values?
|
||||
#{v}
|
||||
(set? v)
|
||||
(first v)
|
||||
:else
|
||||
v))
|
||||
(or
|
||||
(cond
|
||||
(and multiple-values? (or (set? v) (and (coll? v) (empty? v)) (nil? v)))
|
||||
v
|
||||
multiple-values?
|
||||
#{v}
|
||||
(set? v)
|
||||
(first v)
|
||||
:else
|
||||
v)
|
||||
(:logseq.property/default-value property)))
|
||||
self-value-or-embedded? (fn [v]
|
||||
(or (= (:db/id v) (:db/id block))
|
||||
;; property value self embedded
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
[frontend.config :as config]
|
||||
[frontend.context.i18n :refer [t]]
|
||||
[frontend.db :as db]
|
||||
[frontend.db-mixins :as db-mixins]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.search :as search]
|
||||
[frontend.state :as state]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.util :as util]
|
||||
[logseq.db.common.view :as db-view]
|
||||
[logseq.shui.hooks :as hooks]
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
@@ -18,50 +20,71 @@
|
||||
[references]
|
||||
(sort-by second #(> %1 %2) references))
|
||||
|
||||
(defn filtered-refs
|
||||
[page filters filtered-references*]
|
||||
[:div.flex.gap-2.flex-wrap.items-center
|
||||
(let [filtered-references (if (de/entity? (first filtered-references*))
|
||||
(map (fn [e] [(:block/title e)]) filtered-references*)
|
||||
filtered-references*)] <
|
||||
(for [[ref-name ref-count] filtered-references]
|
||||
(when ref-name
|
||||
(let [lc-reference (string/lower-case ref-name)]
|
||||
(ui/button
|
||||
[:span
|
||||
ref-name
|
||||
(when ref-count [:sup " " ref-count])]
|
||||
:on-click (fn [e]
|
||||
(let [db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
includes (set (map :block/name (:included filters)))
|
||||
excludes (set (map :block/name (:excluded filters)))
|
||||
included? (includes lc-reference)
|
||||
not-in-filters? (and (not included?) (not (excludes lc-reference)))
|
||||
shift? (.-shiftKey e)]
|
||||
(if db-based?
|
||||
(page-handler/db-based-save-filter! page (:db/id (db/get-page lc-reference))
|
||||
{:add? not-in-filters?
|
||||
:include? (if not-in-filters? (not shift?) included?)})
|
||||
(let [filters-m (->> (concat (map #(vector % true) includes) (map #(vector % false) excludes))
|
||||
(into {}))
|
||||
filters' (if not-in-filters?
|
||||
(assoc filters-m lc-reference (not shift?))
|
||||
(dissoc filters-m lc-reference))]
|
||||
(page-handler/file-based-save-filter! page filters')))))
|
||||
:small? true
|
||||
:variant :outline
|
||||
:key ref-name)))))])
|
||||
(rum/defc ref-button
|
||||
[page filters ref-name ref-count]
|
||||
(let [lc-reference (string/lower-case ref-name)]
|
||||
(ui/button
|
||||
[:span
|
||||
ref-name
|
||||
(when ref-count [:sup " " ref-count])]
|
||||
:on-click (fn [e]
|
||||
(let [db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
includes (set (map :block/name (:included filters)))
|
||||
excludes (set (map :block/name (:excluded filters)))
|
||||
included? (includes lc-reference)
|
||||
not-in-filters? (and (not included?) (not (excludes lc-reference)))
|
||||
shift? (.-shiftKey e)]
|
||||
(if db-based?
|
||||
(page-handler/db-based-save-filter! page (:db/id (db/get-page lc-reference))
|
||||
{:add? not-in-filters?
|
||||
:include? (if not-in-filters? (not shift?) included?)})
|
||||
(let [filters-m (->> (concat (map #(vector % true) includes) (map #(vector % false) excludes))
|
||||
(into {}))
|
||||
filters' (if not-in-filters?
|
||||
(assoc filters-m lc-reference (not shift?))
|
||||
(dissoc filters-m lc-reference))]
|
||||
(page-handler/file-based-save-filter! page filters')))))
|
||||
:small? true
|
||||
:variant :outline)))
|
||||
|
||||
(rum/defcs filter-dialog < (rum/local "" ::filterSearch) rum/reactive
|
||||
[state page references]
|
||||
(let [page-entity (db/sub-block (:db/id page))
|
||||
filter-search (get state ::filterSearch)
|
||||
(defn filtered-refs
|
||||
[page filters filtered-references* virtual?]
|
||||
(let [filtered-references (if (de/entity? (first filtered-references*))
|
||||
(map (fn [e] [(:block/title e)]) filtered-references*)
|
||||
filtered-references*)]
|
||||
(if (and (> (count filtered-references) 100)
|
||||
(not (false? virtual?)))
|
||||
(ui/virtualized-list
|
||||
{:style {:height 500
|
||||
:width 500
|
||||
:max-width 500}
|
||||
:total-count (count filtered-references)
|
||||
:compute-item-key (fn [idx]
|
||||
(str "ref-button-" idx))
|
||||
:item-content (fn [idx]
|
||||
(let [[ref-name ref-count] (util/nth-safe filtered-references idx)]
|
||||
(ref-button page filters ref-name ref-count)))})
|
||||
[:div.flex.gap-2.flex-wrap.items-center
|
||||
{:style {:width 500
|
||||
:max-width 500}}
|
||||
(for [[ref-name ref-count] filtered-references]
|
||||
(rum/with-key (ref-button page filters ref-name ref-count)
|
||||
(str "ref-" ref-name)))])))
|
||||
|
||||
(rum/defc filter-dialog-aux
|
||||
[page-entity references]
|
||||
(let [[filter-search set-filter-search!] (hooks/use-state "")
|
||||
[filtered-references set-filtered-references!] (hooks/use-state references)
|
||||
filters (db-view/get-filters (db/get-db) page-entity)
|
||||
filtered-references (frequencies-sort
|
||||
(if (= @filter-search "")
|
||||
references
|
||||
(search/fuzzy-search references @filter-search :limit 500 :extract-fn first)))
|
||||
{:keys [included excluded]} filters]
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(let [references (if (= filter-search "")
|
||||
references
|
||||
(->> (search/fuzzy-search references filter-search :limit 100 :extract-fn first)
|
||||
frequencies-sort))]
|
||||
(set-filtered-references! references)))
|
||||
[(hooks/use-debounced-value filter-search 200)])
|
||||
[:div.ls-filters.filters
|
||||
[:div.sm:flex.sm:items-start
|
||||
[:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-gray-200.text-gray-500.sm:mx-0.sm:h-10.sm:w-10
|
||||
@@ -75,12 +98,12 @@
|
||||
(when (seq included)
|
||||
[:div.flex.flex-row.flex-wrap.center-items
|
||||
[:div.mr-1.font-medium.py-1 (t :linked-references/filter-includes)]
|
||||
(filtered-refs page-entity filters included)])
|
||||
(filtered-refs page-entity filters included false)])
|
||||
(when (seq excluded)
|
||||
[:div.flex.flex-row.flex-wrap
|
||||
[:div.mr-1.font-medium.py-1 (t :linked-references/filter-excludes)]
|
||||
|
||||
(filtered-refs page-entity filters excluded)])])
|
||||
(filtered-refs page-entity filters excluded false)])])
|
||||
[:div.cp__filters-input-panel.flex.focus-within:bg-gray-03
|
||||
(ui/icon "search")
|
||||
[:input.cp__filters-input.w-full.bg-transparent
|
||||
@@ -89,7 +112,7 @@
|
||||
:ref (fn [^js el] (when el
|
||||
(-> (p/delay 32) (p/then #(.focus el)))))
|
||||
:on-change (fn [e]
|
||||
(reset! filter-search (util/evalue e)))}]]
|
||||
(set-filter-search! (util/evalue e)))}]]
|
||||
(let [all-filters (set
|
||||
(concat (map :block/name included)
|
||||
(map :block/name excluded)))
|
||||
@@ -97,4 +120,9 @@
|
||||
filtered-references)]
|
||||
(when (seq refs)
|
||||
[:div.mt-4
|
||||
(filtered-refs page-entity filters refs)]))]))
|
||||
(filtered-refs page-entity filters refs true)]))]))
|
||||
|
||||
(rum/defc filter-dialog < rum/reactive db-mixins/query
|
||||
[page references]
|
||||
(let [page-entity (db/sub-block (:db/id page))]
|
||||
(filter-dialog-aux page-entity references)))
|
||||
|
||||
@@ -215,7 +215,11 @@
|
||||
{:align :start})
|
||||
(editor-handler/edit-block! block :max {:container-id :unknown-container}))))))}
|
||||
(if block
|
||||
(inline-title (:block/title block))
|
||||
[:div (inline-title
|
||||
(some->> (:block/title block)
|
||||
string/trim
|
||||
string/split-lines
|
||||
first))]
|
||||
[:div])]))
|
||||
|
||||
(defn build-columns
|
||||
@@ -1220,7 +1224,8 @@
|
||||
db-id (cond (map? item) (:db/id item)
|
||||
(number? item) item
|
||||
:else nil)
|
||||
[item set-item!] (hooks/use-state nil)
|
||||
block (some-> db-id db/entity)
|
||||
[item set-item!] (hooks/use-state (when (:block.temp/fully-loaded? block) block))
|
||||
opts (if list-view?
|
||||
{:skip-refresh? true
|
||||
:children? false}
|
||||
@@ -1251,7 +1256,7 @@
|
||||
(gdom/getElement "main-content-container"))
|
||||
:compute-item-key (fn [idx]
|
||||
(let [block-id (util/nth-safe rows idx)]
|
||||
(str "table-row-" (:group-idx option) "-" block-id)))
|
||||
(str "table-row-" block-id)))
|
||||
:skipAnimationFrameInResizeObserver true
|
||||
:total-count (count rows)
|
||||
:context {:scrolling scrolling?}
|
||||
@@ -1298,8 +1303,8 @@
|
||||
:compute-item-key (fn [idx]
|
||||
(let [block-id (util/nth-safe rows idx)]
|
||||
(str "list-row-" block-id)))
|
||||
;; :skipAnimationFrameInResizeObserver true
|
||||
:total-count (count rows)
|
||||
:skipAnimationFrameInResizeObserver true
|
||||
:item-content (fn [idx] (lazy-item-render rows idx))})))
|
||||
breadcrumb (state/get-component :block/breadcrumb)
|
||||
all-numbers? (every? number? rows)]
|
||||
@@ -1339,6 +1344,9 @@
|
||||
{:ref #(reset! *scroller-ref %)
|
||||
:total-count (count blocks)
|
||||
:custom-scroll-parent (gdom/getElement "main-content-container")
|
||||
:skipAnimationFrameInResizeObserver true
|
||||
:compute-item-key (fn [idx]
|
||||
(str (:db/id view-entity) "-card-" idx))
|
||||
:item-content (fn [idx]
|
||||
(lazy-item (:data table) idx {}
|
||||
(fn [block]
|
||||
@@ -1692,52 +1700,45 @@
|
||||
:add-new-object! add-new-object!}]
|
||||
(if (and group-by-property-ident (not (number? (first (:rows table)))))
|
||||
(when (seq (:rows table))
|
||||
[:div.flex.flex-col.border-t.pt-2
|
||||
(ui/virtualized-list
|
||||
{:class (when list-view? "group-list-view")
|
||||
:custom-scroll-parent (gdom/getElement "main-content-container")
|
||||
:increase-viewport-by {:top 300 :bottom 300}
|
||||
:compute-item-key (fn [idx]
|
||||
(str "table-group" idx))
|
||||
:skipAnimationFrameInResizeObserver true
|
||||
:total-count (count (:rows table))
|
||||
:item-content (fn [idx]
|
||||
(let [[value group] (nth (:rows table) idx)
|
||||
add-new-object! (when (fn? add-new-object!)
|
||||
(fn [_]
|
||||
(add-new-object! view-entity table
|
||||
{:properties {(:db/ident group-by-property) (or (and (map? value) (:db/id value)) value)}})))
|
||||
table' (shui/table-option (-> table-map
|
||||
(assoc-in [:data-fns :add-new-object!] add-new-object!)
|
||||
(assoc :data group ; data for this group
|
||||
)))
|
||||
readable-property-value #(if (and (map? %) (or (:block/title %) (:logseq.property/value %)))
|
||||
(db-property/property-value-content %)
|
||||
(str %))
|
||||
group-by-page? (or (= :block/page group-by-property-ident)
|
||||
(and (not db-based?) (contains? #{:linked-references :unlinked-references} display-type)))]
|
||||
(rum/with-key
|
||||
(ui/foldable
|
||||
[:div
|
||||
(cond
|
||||
group-by-page?
|
||||
(if value
|
||||
(let [c (state/get-component :block/page-cp)]
|
||||
(c {:disable-preview? true} value))
|
||||
[:div.text-muted-foreground.text-sm
|
||||
"Pages"])
|
||||
[:div.flex.flex-col.border-t.pt-2.gap-2
|
||||
(map-indexed
|
||||
(fn [idx [value group]]
|
||||
(let [add-new-object! (when (fn? add-new-object!)
|
||||
(fn [_]
|
||||
(add-new-object! view-entity table
|
||||
{:properties {(:db/ident group-by-property) (or (and (map? value) (:db/id value)) value)}})))
|
||||
table' (shui/table-option (-> table-map
|
||||
(assoc-in [:data-fns :add-new-object!] add-new-object!)
|
||||
(assoc :data group ; data for this group
|
||||
)))
|
||||
readable-property-value #(if (and (map? %) (or (:block/title %) (:logseq.property/value %)))
|
||||
(db-property/property-value-content %)
|
||||
(str %))
|
||||
group-by-page? (or (= :block/page group-by-property-ident)
|
||||
(and (not db-based?) (contains? #{:linked-references :unlinked-references} display-type)))]
|
||||
(rum/with-key
|
||||
(ui/foldable
|
||||
[:div
|
||||
(cond
|
||||
group-by-page?
|
||||
(if value
|
||||
(let [c (state/get-component :block/page-cp)]
|
||||
(c {:disable-preview? true} value))
|
||||
[:div.text-muted-foreground.text-sm
|
||||
"Pages"])
|
||||
|
||||
(some? value)
|
||||
(let [icon (pu/get-block-property-value value :logseq.property/icon)]
|
||||
[:div.flex.flex-row.gap-1.items-center
|
||||
(when icon (icon-component/icon icon {:color? true}))
|
||||
(readable-property-value value)])
|
||||
:else
|
||||
(str "No " (:block/title group-by-property)))]
|
||||
(let [render (view-cp view-entity (assoc table' :rows group :group-idx idx) option view-opts)]
|
||||
(if list-view? [:div.-ml-2 render] render))
|
||||
{:title-trigger? false})
|
||||
(str "group-" idx))))})])
|
||||
(some? value)
|
||||
(let [icon (pu/get-block-property-value value :logseq.property/icon)]
|
||||
[:div.flex.flex-row.gap-1.items-center
|
||||
(when icon (icon-component/icon icon {:color? true}))
|
||||
(readable-property-value value)])
|
||||
:else
|
||||
(str "No " (:block/title group-by-property)))]
|
||||
(let [render (view-cp view-entity (assoc table' :rows group) option view-opts)]
|
||||
(if list-view? [:div.-ml-2 render] render))
|
||||
{:title-trigger? false})
|
||||
(str (:db/id view-entity) "-group-idx-" idx))))
|
||||
(:rows table))])
|
||||
(view-cp view-entity table option view-opts)))]
|
||||
(merge {:title-trigger? false} foldable-options))]))
|
||||
|
||||
@@ -1812,7 +1813,7 @@
|
||||
[(:db/id view-entity)
|
||||
(hooks/use-debounced-value input 300)
|
||||
sorting-filters
|
||||
(:logseq.property.view/group-by-property view-entity)
|
||||
(:db/id (:logseq.property.view/group-by-property view-entity))
|
||||
;; page filters
|
||||
(:logseq.property.linked-references/includes view-parent)
|
||||
(:logseq.property.linked-references/excludes view-parent)
|
||||
|
||||
@@ -793,7 +793,7 @@ independent of format as format specific heading characters are stripped"
|
||||
|
||||
(defn get-all-namespace-relation
|
||||
[repo]
|
||||
(ldb/get-all-namespace-relation (conn/get-db repo)))
|
||||
(gp-db/get-all-namespace-relation (conn/get-db repo)))
|
||||
|
||||
(defn get-all-namespace-parents
|
||||
[repo]
|
||||
|
||||
@@ -104,7 +104,9 @@
|
||||
(defn- handle-connection-change
|
||||
[e]
|
||||
(let [online? (= (gobj/get e "type") "online")]
|
||||
(state/set-online! online?)))
|
||||
(state/set-online! online?)
|
||||
(state/<invoke-db-worker :thread-api/update-thread-atom
|
||||
:thread-atom/online-event online?)))
|
||||
|
||||
(defn set-network-watcher!
|
||||
[]
|
||||
@@ -155,7 +157,6 @@
|
||||
(i18n/start)
|
||||
(instrument/init)
|
||||
(state/set-online! js/navigator.onLine)
|
||||
(set-network-watcher!)
|
||||
|
||||
(-> (util/indexeddb-check?)
|
||||
(p/catch (fn [_e]
|
||||
@@ -177,6 +178,7 @@
|
||||
_ (if (empty? repos)
|
||||
(repo-handler/new-db! config/demo-repo)
|
||||
(restore-and-setup! repo))]
|
||||
(set-network-watcher!)
|
||||
(when (util/electron?)
|
||||
(persist-db/run-export-periodically!))
|
||||
(when (mobile-util/native-platform?)
|
||||
|
||||
@@ -77,8 +77,8 @@
|
||||
(def edit-block! block-handler/edit-block!)
|
||||
|
||||
(defn- outliner-save-block!
|
||||
[block]
|
||||
(outliner-op/save-block! block))
|
||||
[block & {:as opts}]
|
||||
(outliner-op/save-block! block opts))
|
||||
|
||||
(defn get-block-own-order-list-type
|
||||
[block]
|
||||
@@ -3642,7 +3642,7 @@
|
||||
(when-not (= current-value value)
|
||||
(let [block {:block/uuid block-id
|
||||
:block/collapsed? value}]
|
||||
(outliner-save-block! block)))))))
|
||||
(outliner-save-block! block {:outliner-op :collapse-expand-blocks})))))))
|
||||
(doseq [block-id block-ids]
|
||||
(state/set-collapsed-block! block-id value)))))
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
(p/let [result (export-common-handler/<get-debug-datoms repo)
|
||||
filename (file-name (str repo "-debug-datoms") :transit)
|
||||
data-str (str "data:text/transit;charset=utf-8,"
|
||||
(js/encodeURIComponent result))]
|
||||
(js/encodeURIComponent (ldb/write-transit-str result)))]
|
||||
(when-let [anchor (gdom/getElement "download-as-transit-debug")]
|
||||
(.setAttribute anchor "href" data-str)
|
||||
(.setAttribute anchor "download" filename)
|
||||
|
||||
@@ -544,7 +544,13 @@
|
||||
(boolean
|
||||
(some
|
||||
;; check if there's any entity reference this `block` except the view-entity
|
||||
(fn [ref] (not= id (:db/id (:logseq.property/view-for ref))))
|
||||
(fn [ref]
|
||||
(not
|
||||
(or (= id (:db/id (:logseq.property/view-for ref)))
|
||||
(ldb/hidden? (:block/page ref))
|
||||
(ldb/hidden? ref)
|
||||
(contains? (set (map :db/id (:block/tags ref))) id)
|
||||
(some? (get ref (:db/ident block))))))
|
||||
(:block/_refs block)))))))
|
||||
|
||||
(def-thread-api :thread-api/get-block-parents
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
(if (and (contains? #{:block/title :block/name} a)
|
||||
(let [entity (d/entity @conn e)]
|
||||
(and (not (:db/ident entity))
|
||||
(not (ldb/journal? entity)))))
|
||||
(not (ldb/journal? entity))
|
||||
(not (:logseq.property/built-in? entity)))))
|
||||
(d/datom e a (str "debug " e) t)
|
||||
(d/datom e a v t))))))
|
||||
|
||||
13
src/main/frontend/worker/flows.cljs
Normal file
13
src/main/frontend/worker/flows.cljs
Normal file
@@ -0,0 +1,13 @@
|
||||
(ns frontend.worker.flows
|
||||
"common flows in worker thread"
|
||||
(:require [frontend.worker.state :as worker-state]
|
||||
[missionary.core :as m]))
|
||||
|
||||
(def online-event-flow
|
||||
(->> (m/watch (get @worker-state/*state :thread-atom/online-event))
|
||||
(m/eduction
|
||||
(drop-while nil?)
|
||||
(filter true?))))
|
||||
|
||||
(comment
|
||||
((m/reduce (fn [_ x] (prn :xxx x)) online-event-flow) prn prn))
|
||||
@@ -3,6 +3,7 @@
|
||||
(:require [clojure.string :as string]
|
||||
[datascript.core :as d]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[frontend.worker.flows :as worker-flows]
|
||||
[frontend.worker.rtc.branch-graph :as r.branch-graph]
|
||||
[frontend.worker.rtc.client-op :as client-op]
|
||||
[frontend.worker.rtc.exception :as r.ex]
|
||||
@@ -64,7 +65,10 @@
|
||||
(let [{:keys [max-remote-schema-version]}
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
(take 5 (drop 2 c.m/delays)) ;retry 5 times if remote-graph is creating (4000 8000 16000 32000 64000)
|
||||
{:delay-seq
|
||||
;retry 5 times if remote-graph is creating (4000 8000 16000 32000 64000)
|
||||
(take 5 (drop 2 c.m/delays))
|
||||
:reset-flow worker-flows/online-event-flow}
|
||||
(new-task--register-graph-updates get-ws-create-task graph-uuid major-schema-version repo)))]
|
||||
(when max-remote-schema-version
|
||||
(add-log-fn :rtc.log/higher-remote-schema-version-exists
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
https://github.com/ReilySiegel/missionary-websocket/blob/master/src/com/reilysiegel/missionary/websocket.cljs"
|
||||
(:require [cljs-http-missionary.client :as http]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[frontend.worker.flows :as worker-flows]
|
||||
[frontend.worker.rtc.exception :as r.ex]
|
||||
[frontend.worker.rtc.malli-schema :as rtc-schema]
|
||||
[missionary.core :as m]))
|
||||
@@ -88,7 +89,8 @@
|
||||
(pos-int? open-ws-timeout))
|
||||
[retry-count open-ws-timeout])
|
||||
(c.m/backoff
|
||||
(take retry-count c.m/delays)
|
||||
{:delay-seq (take retry-count c.m/delays)
|
||||
:reset-flow worker-flows/online-event-flow}
|
||||
(m/sp
|
||||
(try
|
||||
(if-let [ws (m/? (m/timeout (create-mws* url) open-ws-timeout))]
|
||||
|
||||
@@ -36,7 +36,11 @@
|
||||
:auth/access-token nil
|
||||
:auth/refresh-token nil
|
||||
|
||||
:rtc/downloading-graph? false}))
|
||||
:rtc/downloading-graph? false
|
||||
|
||||
;; thread atoms, these atoms' value are syncing from ui-thread
|
||||
:thread-atom/online-event (atom nil)
|
||||
}))
|
||||
|
||||
(defonce *rtc-ws-url (atom nil))
|
||||
|
||||
|
||||
12
src/main/frontend/worker/thread_atom.cljs
Normal file
12
src/main/frontend/worker/thread_atom.cljs
Normal file
@@ -0,0 +1,12 @@
|
||||
(ns frontend.worker.thread-atom
|
||||
"atoms from ui-thread"
|
||||
(:require [frontend.common.thread-api :as thread-api :refer [def-thread-api]]
|
||||
[frontend.worker.state :as worker-state]))
|
||||
|
||||
(def-thread-api :thread-api/update-thread-atom
|
||||
[atom-key new-value]
|
||||
(assert (and (keyword? atom-key)
|
||||
(identical? "thread-atom" (namespace atom-key))))
|
||||
(when-let [a (get @worker-state/*state atom-key)]
|
||||
(reset! a new-value)
|
||||
nil))
|
||||
@@ -44,7 +44,7 @@
|
||||
(is (nil? r)))
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
page1 (d/pull @conn '[*] [:block/uuid const/page1-uuid])
|
||||
@@ -72,7 +72,7 @@
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))))
|
||||
:client2
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
page (d/pull @conn '[*] [:block/uuid const/page2-uuid])]
|
||||
@@ -107,7 +107,7 @@
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))))
|
||||
:client2
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
block1 (d/pull @conn
|
||||
@@ -231,7 +231,7 @@ client2:
|
||||
(m/? (helper/new-task--client2-sync-barrier-1->2 "step6"))
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [page (d/pull @conn '[*] [:block/uuid const/step6-page-uuid])
|
||||
page-blocks (when-let [page-id (:db/id page)]
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
(defn new-task--wait-creating-graph
|
||||
[graph-uuid]
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [graphs (m/? (rtc.core/new-task--get-graphs const/test-token))
|
||||
graph (some (fn [graph] (when (= graph-uuid (:graph-uuid graph)) graph)) graphs)]
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
(def new-task--get-remote-example-graph-uuid
|
||||
(c.m/backoff
|
||||
(take 5 c.m/delays)
|
||||
{}
|
||||
(m/sp
|
||||
(let [graphs (m/? (rtc.core/new-task--get-graphs const/test-token))
|
||||
graph
|
||||
@@ -94,11 +94,11 @@
|
||||
#_:clj-kondo/ignore
|
||||
(me/find
|
||||
client-op
|
||||
[?op-type _ {:block-uuid ?block-uuid :av-coll [[!a !v _ !add] ...]}]
|
||||
[?op-type ?block-uuid (map vector !a !v !add)]
|
||||
[?op-type _ {:block-uuid ?block-uuid :av-coll [[!a !v _ !add] ...]}]
|
||||
[?op-type ?block-uuid (map vector !a !v !add)]
|
||||
|
||||
[?op-type _ {:block-uuid ?block-uuid}]
|
||||
[?op-type ?block-uuid]))
|
||||
[?op-type _ {:block-uuid ?block-uuid}]
|
||||
[?op-type ?block-uuid]))
|
||||
|
||||
(defn new-task--wait-all-client-ops-sent
|
||||
[& {:keys [timeout] :or {timeout 10000}}]
|
||||
@@ -144,7 +144,7 @@
|
||||
"Return a task that return message from other client"
|
||||
[block-title-pred-fn & {:keys [retry-message retry-count] :or {retry-count 4}}]
|
||||
(c.m/backoff
|
||||
(take retry-count c.m/delays)
|
||||
{:delay-seq (take retry-count c.m/delays)}
|
||||
(m/sp
|
||||
(let [conn (get-downloaded-test-conn)
|
||||
message-page-id (:db/id (ldb/get-page @conn const/message-page-uuid))
|
||||
|
||||
Reference in New Issue
Block a user