Fase B1: chain journal pages with previous/next graph links
Adds :logseq.property.journal/previous and /next (built-in, hidden, single-cardinality node refs) and maintains them in logseq.outliner.page/create whenever a new journal page is created. Filling a gap between two already-linked journals re-links both neighbors around the new page instead of just appending. A migration backfills the chain across all existing journal pages ordered by day.
This commit is contained in:
13
deps/db/src/logseq/db/frontend/property.cljs
vendored
13
deps/db/src/logseq/db/frontend/property.cljs
vendored
@@ -265,11 +265,24 @@
|
|||||||
:public? false
|
:public? false
|
||||||
:hide? true}}
|
:hide? true}}
|
||||||
|
|
||||||
|
:logseq.property.citation/target {:title "Cited page or block"
|
||||||
|
:schema {:type :node}}
|
||||||
|
:logseq.property.citation/context {:title "Citation context"
|
||||||
|
:schema {:type :string}}
|
||||||
|
|
||||||
;; Journal props
|
;; Journal props
|
||||||
:logseq.property.journal/title-format {:title "Title Format"
|
:logseq.property.journal/title-format {:title "Title Format"
|
||||||
:schema
|
:schema
|
||||||
{:type :string
|
{:type :string
|
||||||
:public? false}}
|
:public? false}}
|
||||||
|
:logseq.property.journal/previous {:title "Previous journal"
|
||||||
|
:schema {:type :node
|
||||||
|
:hide? true
|
||||||
|
:public? false}}
|
||||||
|
:logseq.property.journal/next {:title "Next journal"
|
||||||
|
:schema {:type :node
|
||||||
|
:hide? true
|
||||||
|
:public? false}}
|
||||||
|
|
||||||
:logseq.property/choice-checkbox-state {:title "Choice checkbox state"
|
:logseq.property/choice-checkbox-state {:title "Choice checkbox state"
|
||||||
:schema {:type :checkbox
|
:schema {:type :checkbox
|
||||||
|
|||||||
2
deps/db/src/logseq/db/frontend/schema.cljs
vendored
2
deps/db/src/logseq/db/frontend/schema.cljs
vendored
@@ -30,7 +30,7 @@
|
|||||||
(map (juxt :major :minor)
|
(map (juxt :major :minor)
|
||||||
[(parse-schema-version x) (parse-schema-version y)])))
|
[(parse-schema-version x) (parse-schema-version y)])))
|
||||||
|
|
||||||
(def version (parse-schema-version "65.33"))
|
(def version (parse-schema-version "65.36"))
|
||||||
|
|
||||||
(defn major-version
|
(defn major-version
|
||||||
"Return a number.
|
"Return a number.
|
||||||
|
|||||||
39
deps/outliner/src/logseq/outliner/page.cljs
vendored
39
deps/outliner/src/logseq/outliner/page.cljs
vendored
@@ -299,6 +299,40 @@
|
|||||||
[page])
|
[page])
|
||||||
(remove nil?))))
|
(remove nil?))))
|
||||||
|
|
||||||
|
(defn- journal-neighbors
|
||||||
|
"Returns [prev-entity next-entity], the closest existing journal pages
|
||||||
|
immediately before/after journal-day (by day order, not necessarily
|
||||||
|
adjacent calendar days)."
|
||||||
|
[db journal-day]
|
||||||
|
(let [entries (->> (d/datoms db :avet :block/journal-day)
|
||||||
|
(map (fn [datom] [(:v datom) (:e datom)]))
|
||||||
|
(remove (fn [[day]] (= day journal-day))))
|
||||||
|
prev (->> entries (filter #(< (first %) journal-day)) (sort-by first) last)
|
||||||
|
next (->> entries (filter #(> (first %) journal-day)) (sort-by first) first)]
|
||||||
|
[(some->> prev second (d/entity db))
|
||||||
|
(some->> next second (d/entity db))]))
|
||||||
|
|
||||||
|
(defn- journal-relink-tx
|
||||||
|
"Tx-data linking a newly created journal page (identified by its uuid) to
|
||||||
|
its nearest existing journal neighbors by day. Re-links around the new
|
||||||
|
page when it fills a gap between two already-linked journals."
|
||||||
|
[db page-uuid journal-day]
|
||||||
|
(let [[prev next] (journal-neighbors db journal-day)
|
||||||
|
page-ref [:block/uuid page-uuid]]
|
||||||
|
(concat
|
||||||
|
(when prev
|
||||||
|
(cond-> [[:db/add page-ref :logseq.property.journal/previous (:db/id prev)]
|
||||||
|
[:db/add (:db/id prev) :logseq.property.journal/next page-ref]]
|
||||||
|
(:logseq.property.journal/next prev)
|
||||||
|
(conj [:db/retract (:db/id prev) :logseq.property.journal/next
|
||||||
|
(:db/id (:logseq.property.journal/next prev))])))
|
||||||
|
(when next
|
||||||
|
(cond-> [[:db/add page-ref :logseq.property.journal/next (:db/id next)]
|
||||||
|
[:db/add (:db/id next) :logseq.property.journal/previous page-ref]]
|
||||||
|
(:logseq.property.journal/previous next)
|
||||||
|
(conj [:db/retract (:db/id next) :logseq.property.journal/previous
|
||||||
|
(:db/id (:logseq.property.journal/previous next))]))))))
|
||||||
|
|
||||||
(defn ^:large-vars/cleanup-todo ^:api create
|
(defn ^:large-vars/cleanup-todo ^:api create
|
||||||
"Pure function without side effects"
|
"Pure function without side effects"
|
||||||
[db title*
|
[db title*
|
||||||
@@ -403,10 +437,13 @@
|
|||||||
(:block/uuid page))
|
(:block/uuid page))
|
||||||
page (assoc page :block/uuid page-uuid)
|
page (assoc page :block/uuid page-uuid)
|
||||||
page-txs (build-page-tx db properties page (select-keys options [:class? :tags :class-ident-namespace]))
|
page-txs (build-page-tx db properties page (select-keys options [:class? :tags :class-ident-namespace]))
|
||||||
|
journal-link-txs (when-let [journal-day (:block/journal-day page)]
|
||||||
|
(journal-relink-tx db page-uuid journal-day))
|
||||||
txs (concat
|
txs (concat
|
||||||
;; transact doesn't support entities
|
;; transact doesn't support entities
|
||||||
(remove de/entity? parents')
|
(remove de/entity? parents')
|
||||||
page-txs)
|
page-txs
|
||||||
|
journal-link-txs)
|
||||||
tx-meta (cond-> (outliner-tx-meta/ensure-outliner-ops
|
tx-meta (cond-> (outliner-tx-meta/ensure-outliner-ops
|
||||||
{:persist-op? persist-op?
|
{:persist-op? persist-op?
|
||||||
:outliner-op :create-page}
|
:outliner-op :create-page}
|
||||||
|
|||||||
@@ -204,3 +204,48 @@
|
|||||||
"Journal title is not split into a month namespace page")
|
"Journal title is not split into a month namespace page")
|
||||||
(is (nil? (ldb/get-page @conn "18"))
|
(is (nil? (ldb/get-page @conn "18"))
|
||||||
"Journal title is not split into a day namespace page")))
|
"Journal title is not split into a day namespace page")))
|
||||||
|
|
||||||
|
(deftest create-journal-links-previous-and-next
|
||||||
|
(let [conn (db-test/create-conn)
|
||||||
|
[_ day1-uuid] (outliner-page/create! conn "Dec 16th, 2024" {})
|
||||||
|
[_ day2-uuid] (outliner-page/create! conn "Dec 17th, 2024" {})
|
||||||
|
day1 (d/entity @conn [:block/uuid day1-uuid])
|
||||||
|
day2 (d/entity @conn [:block/uuid day2-uuid])]
|
||||||
|
(is (nil? (:logseq.property.journal/previous day1))
|
||||||
|
"First journal has no previous")
|
||||||
|
(is (= day2-uuid (:block/uuid (:logseq.property.journal/next day1)))
|
||||||
|
"First journal links forward to the second")
|
||||||
|
(is (= day1-uuid (:block/uuid (:logseq.property.journal/previous day2)))
|
||||||
|
"Second journal links back to the first")
|
||||||
|
(is (nil? (:logseq.property.journal/next day2))
|
||||||
|
"Second journal has no next yet")))
|
||||||
|
|
||||||
|
(deftest create-journal-fills-gap-relinks-neighbors
|
||||||
|
(let [conn (db-test/create-conn)
|
||||||
|
[_ day1-uuid] (outliner-page/create! conn "Dec 16th, 2024" {})
|
||||||
|
[_ day3-uuid] (outliner-page/create! conn "Dec 18th, 2024" {})
|
||||||
|
[_ day2-uuid] (outliner-page/create! conn "Dec 17th, 2024" {})
|
||||||
|
day1 (d/entity @conn [:block/uuid day1-uuid])
|
||||||
|
day2 (d/entity @conn [:block/uuid day2-uuid])
|
||||||
|
day3 (d/entity @conn [:block/uuid day3-uuid])]
|
||||||
|
(is (= day2-uuid (:block/uuid (:logseq.property.journal/next day1)))
|
||||||
|
"Day1 now points to the newly created day2, not day3")
|
||||||
|
(is (= day1-uuid (:block/uuid (:logseq.property.journal/previous day2)))
|
||||||
|
"Day2 points back to day1")
|
||||||
|
(is (= day3-uuid (:block/uuid (:logseq.property.journal/next day2)))
|
||||||
|
"Day2 points forward to day3")
|
||||||
|
(is (= day2-uuid (:block/uuid (:logseq.property.journal/previous day3)))
|
||||||
|
"Day3 now points back to day2, not day1")))
|
||||||
|
|
||||||
|
(deftest create-namespace-page-under-contents
|
||||||
|
(let [conn (db-test/create-conn)
|
||||||
|
[_ child-uuid] (outliner-page/create! conn (str common-config/contents-page-name "/rama") {:split-namespace? true})
|
||||||
|
child-page (d/entity @conn [:block/uuid child-uuid])
|
||||||
|
contents (ldb/get-contents-page @conn)
|
||||||
|
library (ldb/get-built-in-page @conn common-config/library-page-name)]
|
||||||
|
(is (= "rama" (:block/title child-page)))
|
||||||
|
(is (= (:db/id contents) (:db/id (:block/parent child-page)))
|
||||||
|
"Contents can be used as an explicit parent root, alongside Library")
|
||||||
|
(is (empty? (:block/_parent library))
|
||||||
|
"Library is untouched when a page is nested under Contents instead")
|
||||||
|
(is (ldb/contents? contents))))
|
||||||
|
|||||||
@@ -120,6 +120,18 @@
|
|||||||
[[:db/retract (:db/id class) :block/order (:block/order class)]]))))
|
[[:db/retract (:db/id class) :block/order (:block/order class)]]))))
|
||||||
[:logseq.class/Comments :logseq.class/Comment]))))
|
[:logseq.class/Comments :logseq.class/Comment]))))
|
||||||
|
|
||||||
|
(defn- link-existing-journals
|
||||||
|
"Backfill :logseq.property.journal/previous and /next across all existing
|
||||||
|
journal pages, ordered by :block/journal-day."
|
||||||
|
[db]
|
||||||
|
(let [journal-pages (->> (d/datoms db :avet :block/journal-day)
|
||||||
|
(map (fn [datom] (d/entity db (:e datom))))
|
||||||
|
(sort-by :block/journal-day))]
|
||||||
|
(->> (partition 2 1 journal-pages)
|
||||||
|
(mapcat (fn [[a b]]
|
||||||
|
[[:db/add (:db/id a) :logseq.property.journal/next (:db/id b)]
|
||||||
|
[:db/add (:db/id b) :logseq.property.journal/previous (:db/id a)]])))))
|
||||||
|
|
||||||
(def schema-version->updates
|
(def schema-version->updates
|
||||||
"A vec of tuples defining datascript migrations. Each tuple consists of the
|
"A vec of tuples defining datascript migrations. Each tuple consists of the
|
||||||
schema version integer and a migration map. A migration map can have keys of :properties, :classes
|
schema version integer and a migration map. A migration map can have keys of :properties, :classes
|
||||||
@@ -162,7 +174,12 @@
|
|||||||
:logseq.property.view/gallery-display-properties
|
:logseq.property.view/gallery-display-properties
|
||||||
:logseq.property.view/gallery-card-size
|
:logseq.property.view/gallery-card-size
|
||||||
:logseq.property.view/gallery-card-width
|
:logseq.property.view/gallery-card-width
|
||||||
:logseq.property.view/gallery-card-height]}]])
|
:logseq.property.view/gallery-card-height]}]
|
||||||
|
["65.34" {:properties [:logseq.property.journal/previous :logseq.property.journal/next]
|
||||||
|
:fix link-existing-journals}]
|
||||||
|
["65.35" {:classes [:logseq.class/Project :logseq.class/Area]}]
|
||||||
|
["65.36" {:classes [:logseq.class/Citation]
|
||||||
|
:properties [:logseq.property.citation/target :logseq.property.citation/context]}]])
|
||||||
|
|
||||||
(let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
|
(let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
|
||||||
schema-version->updates)))]
|
schema-version->updates)))]
|
||||||
@@ -185,7 +202,7 @@
|
|||||||
(= "logseq.kv" (some-> (:db/ident data) namespace))
|
(= "logseq.kv" (some-> (:db/ident data) namespace))
|
||||||
nil
|
nil
|
||||||
|
|
||||||
(= (:block/title data) "Contents")
|
(= (:block/title data) common-config/contents-page-name)
|
||||||
nil
|
nil
|
||||||
|
|
||||||
(:file/path data)
|
(:file/path data)
|
||||||
|
|||||||
Reference in New Issue
Block a user