Fix external asset rendering and journal import namespace handling (#12673)

* fix render external asset fail

* fix: handle nil stat in exteranal asset size calculation

* fix: normalize journal UUIDs and prevent namespace creation for slash-formatted journals

* fix: update journal UUID generation and prevent namespace creation for slash-formatted journals

* fix(import): avoid namespace pages for slash journal refs

* fix: clarify journal uuid option docs

Agent-Logs-Url: https://github.com/logseq/logseq/sessions/d8292bbe-fc6f-4c74-91cd-5705571a89b2

Co-authored-by: tiensonqin <479169+tiensonqin@users.noreply.github.com>

---------

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tiensonqin <479169+tiensonqin@users.noreply.github.com>
This commit is contained in:
megayu
2026-05-21 12:04:02 +08:00
committed by GitHub
parent b1008c281f
commit d130d72579
13 changed files with 308 additions and 39 deletions

View File

@@ -328,6 +328,7 @@
original-page-name (common-util/remove-boundary-slashes original-page-name)
[original-page-name' page-name journal-day] (convert-page-if-journal original-page-name date-formatter {:export-to-db-graph? @*export-to-db-graph?})
namespace? (and (or (not db-based?) @*export-to-db-graph?)
(not journal-day)
(not (boolean (text/get-nested-page-name original-page-name')))
(text/namespace-page? original-page-name'))
page-entity (when (and db (not skip-existing-page-check?))
@@ -442,7 +443,9 @@
p)]
(when (string? p)
(let [p (or (text/get-nested-page-name p) p)]
(if (and (text/namespace-page? p) (not tag?))
(if (and (text/namespace-page? p)
(not (common-date/valid-journal-title-with-slash? p))
(not tag?))
(common-util/split-namespace-pages p)
[p])))))
col)

View File

@@ -177,7 +177,8 @@
:page-names (sort (keys @page-names-to-uuids))})))))
(defn- replace-namespace-with-parent [block page-names-to-uuids parent-k]
(if (:block/namespace block)
(if (and (:block/namespace block)
(not (:block/journal-day block)))
(-> (dissoc block :block/namespace)
(assoc parent-k
{:block/uuid (get-page-uuid page-names-to-uuids
@@ -1571,14 +1572,15 @@
(not (get @assets asset-link-or-name))
(string/ends-with? path ".pdf")
(fn? <get-file-stat))
(-> (p/let [^js stat (<get-file-stat path)]
(-> (p/let [stat (<get-file-stat path)]
(swap! assets assoc asset-link-or-name
{:asset-id (d/squuid)
:type "pdf"
;; avoid using the real checksum since it could be the same with in-graph asset
:checksum "0000000000000000000000000000000000000000000000000000000000000000"
;; gracefully create stat-less assets so that references to them are still valid
:size (if stat (.-size stat) 0)
;; Electron IPC returns a CLJS map, while Node import scripts return fs.Stats.
:size (or (:size stat) (some-> stat .-size) 0)
:external-url (or asset-link-or-name path)
:external-file-name asset-path}))
(p/catch (fn [error]
@@ -2017,7 +2019,7 @@
(cond-> page'
true
(dissoc :block/format)
(:block/namespace page)
(and (:block/namespace page) (not (:block/journal-day page)))
((fn [block']
(merge (build-new-namespace-page block')
{;; save original name b/c it's still used for a few name lookups
@@ -2523,6 +2525,68 @@
(when (seq tx)
(d/transact! conn tx))))
(defn- journal-uuid-normalizations
[db]
(keep (fn [datom]
(let [entity (d/entity db (:e datom))
old-uuid (:block/uuid entity)
journal-day (:block/journal-day entity)
standard-uuid (common-uuid/gen-uuid :journal-page-uuid journal-day)]
(when (and old-uuid (not= old-uuid standard-uuid))
(when-let [target (d/entity db [:block/uuid standard-uuid])]
(when (not= (:db/id target) (:db/id entity))
(throw (ex-info "Cannot normalize journal uuid because the standard uuid is already used"
{:journal-day journal-day
:old-uuid old-uuid
:standard-uuid standard-uuid
:target-id (:db/id target)}))))
{:eid (:db/id entity)
:old-uuid old-uuid
:standard-uuid standard-uuid})))
(d/datoms db :avet :block/journal-day)))
(defn- replace-journal-uuid-refs
[value uuid-replacements]
(if (seq uuid-replacements)
(walk/postwalk
(fn [x]
(if (string? x)
(reduce (fn [s [old-uuid standard-uuid]]
(-> s
(string/replace (page-ref/->page-ref old-uuid)
(page-ref/->page-ref standard-uuid))
(string/replace (block-ref/->block-ref old-uuid)
(block-ref/->block-ref standard-uuid))))
x
uuid-replacements)
x))
value)
value))
(defn- normalize-journal-uuids-tx
[db]
(let [normalizations (vec (journal-uuid-normalizations db))
uuid-replacements (map (juxt :old-uuid :standard-uuid) normalizations)
uuid-tx (mapcat (fn [{:keys [eid old-uuid standard-uuid]}]
[[:db/retract eid :block/uuid old-uuid]
[:db/add eid :block/uuid standard-uuid]])
normalizations)
text-tx (when (seq uuid-replacements)
(keep (fn [datom]
(let [value (:v datom)
value' (when (or (string? value) (coll? value))
(replace-journal-uuid-refs value uuid-replacements))]
(when (and (some? value') (not= value value'))
[:db/add (:e datom) (:a datom) value'])))
(d/datoms db :eavt)))]
(vec (concat uuid-tx text-tx))))
(defn- normalize-journal-uuids!
[conn]
(let [tx (normalize-journal-uuids-tx @conn)]
(when (seq tx)
(d/transact! conn tx))))
(defn export-doc-files
"Exports all user created files i.e. under journals/ and pages/.
Recommended to use build-doc-options and pass that as options"
@@ -2544,9 +2608,11 @@
(p/recur (export-doc-file (get doc-files (inc i)) conn <read-file options)
(inc i))))
(p/then (fn [_]
(p/let [tx-report (cleanup-missing-block-refs! conn)
_ (when tx-report (on-tx-report tx-report))]
tx-report)))
(p/let [normalize-tx-report (normalize-journal-uuids! conn)
_ (when normalize-tx-report (on-tx-report normalize-tx-report))
cleanup-tx-report (cleanup-missing-block-refs! conn)
_ (when cleanup-tx-report (on-tx-report cleanup-tx-report))]
cleanup-tx-report)))
(p/catch (fn [e]
(notify-user {:msg (str "Import has unexpected error:\n" (.-message e))
:level :error

View File

@@ -11,6 +11,7 @@
[clojure.walk :as walk]
[datascript.core :as d]
[logseq.common.util :as common-util]
[logseq.common.uuid :as common-uuid]
[logseq.db :as ldb]
[logseq.graph-parser.block :as gp-block]
[logseq.graph-parser.mldoc :as gp-mldoc]
@@ -188,7 +189,8 @@
(defn- build-pages-aux
[db page-map ref-pages date-formatter format]
(let [namespace-pages (let [page (:block/title page-map)]
(when (text/namespace-page? page)
(when (and (not (:block/journal-day page-map))
(text/namespace-page? page))
(->> (common-util/split-namespace-pages page)
(map (fn [page]
(-> (gp-block/page-name->map page db true date-formatter)
@@ -204,9 +206,11 @@
pages (common-util/distinct-by :block/name pages)
pages (remove nil? pages)]
(map (fn [page]
(let [page-id (or (when db
(:block/uuid (ldb/get-page db (:block/name page))))
(d/squuid))]
(let [page-id (if-let [journal-day (:block/journal-day page)]
(common-uuid/gen-uuid :journal-page-uuid journal-day)
(or (when db
(:block/uuid (ldb/get-page db (:block/name page))))
(d/squuid)))]
(assoc page :block/uuid page-id)))
pages)))
@@ -299,9 +303,11 @@
[pages]
(->> (common-util/distinct-by :block/name pages)
(map (fn [page]
(if (:block/uuid page)
page
(assoc page :block/uuid (d/squuid)))))))
(if-let [journal-day (:block/journal-day page)]
(assoc page :block/uuid (common-uuid/gen-uuid :journal-page-uuid journal-day))
(cond-> page
(nil? (:block/uuid page))
(assoc :block/uuid (d/squuid))))))))
(defn with-ref-pages
[pages blocks]

View File

@@ -1,6 +1,7 @@
(ns logseq.graph-parser.block-test
(:require [cljs.test :refer [deftest are testing is]]
[datascript.core :as d]
[logseq.common.uuid :as common-uuid]
[logseq.graph-parser.block :as gp-block]
[logseq.graph-parser.mldoc :as gp-mldoc]))
@@ -106,6 +107,17 @@
{:property-pages/enabled? true})))
"Only editable linkable built-in properties have page-refs in property values")))
(deftest test-page-name-map-namespace-for-slash-journals
(testing "slash-formatted journals do not keep namespace metadata"
(let [journal (gp-block/page-name->map "2026/05/18" nil false "yyyy/MM/dd")]
(is (= 20260518 (:block/journal-day journal)))
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260518)
(:block/uuid journal)))
(is (nil? (:block/namespace journal)))))
(testing "non-journal slash pages keep namespace metadata"
(is (= {:block/name "project"}
(:block/namespace (gp-block/page-name->map "project/child" nil false "yyyy/MM/dd"))))))
(defn find-block-for-content
[db content]
(->> (d/q '[:find (pull ?b [* {:block/refs [:block/uuid]}])
@@ -114,4 +126,4 @@
db
content)
(map first)
first))
first))

View File

@@ -9,7 +9,10 @@
[logseq.common.config :as common-config]
[logseq.common.graph :as common-graph]
[logseq.common.path :as path]
[logseq.common.util.block-ref :as block-ref]
[logseq.common.util.date-time :as date-time-util]
[logseq.common.util.page-ref :as page-ref]
[logseq.common.uuid :as common-uuid]
[logseq.db :as ldb]
[logseq.db.common.entity-plus :as entity-plus]
[logseq.db.frontend.asset :as db-asset]
@@ -1296,6 +1299,91 @@
(:logseq.property/page-tags (db-test/readable-properties (db-test/find-page-by-title @conn "chat-gpt"))))
"tagged page has new page and other pages marked with '#' and '[[]]` imported as tags to page-tags")))))
(deftest-async import-journals-use-standard-uuids-and-keep-uuid-refs
(p/let [file-graph-dir "test/resources/exporter-test-graph"
files (mapv #(path/path-join file-graph-dir %) ["journals/2026_01_27.md"])
conn (db-test/create-conn)
_ (import-files-to-db files conn {})]
(let [journal (db-test/find-journal-by-journal-day @conn 20260127)
ref-journal (db-test/find-journal-by-journal-day @conn 20260101)
ref-block (some->> (d/q '[:find [?b ...]
:in $ ?page ?ref-page
:where
[?b :block/page ?page]
[?b :block/refs ?ref-page]]
@conn (:db/id journal) (:db/id ref-journal))
first
(d/entity @conn))]
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260127)
(:block/uuid journal))
"Imported journal page keeps the standard journal uuid")
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260101)
(:block/uuid ref-journal))
"Referenced journal page keeps the standard journal uuid")
(is (= #{(:block/uuid ref-journal)}
(set (map :block/uuid (:block/refs ref-block))))
"Journal refs point at the standard journal uuid"))))
(deftest-async import-journal-with-slash-title-format-does-not-create-namespace-pages
(p/let [file-graph-dir "test/resources/exporter-test-graph"
files (mapv #(path/path-join file-graph-dir %) ["journals/2026_01_27.md"])
conn (db-test/create-conn)
_ (import-files-to-db files conn {:user-config {:journal/page-title-format "yyyy/MM/dd"}})
journal (db-test/find-journal-by-journal-day @conn 20260127)]
(is (= "2026/01/27" (:block/title journal))
"Journal title follows slash title format")
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260127)
(:block/uuid journal))
"Slash-formatted journal keeps the standard journal uuid")
(is (nil? (:block/namespace journal))
"Slash-formatted journal does not keep a namespace attribute")
(is (nil? (db-test/find-page-by-title @conn "2026"))
"Journal title is not split into a year namespace page")
(is (nil? (db-test/find-page-by-title @conn "01"))
"Journal title is not split into a month namespace page")
(is (nil? (db-test/find-page-by-title @conn "27"))
"Journal title is not split into a day namespace page")))
(deftest-async import-slash-journal-ref-does-not-create-namespace-pages
(p/let [file (write-temp-graph-file "journals/2026_05_18.md" "- yes\n- [[Sun, 2026/05/17]]\n")
conn (db-test/create-conn)
_ (import-files-to-db [file] conn {:user-config {:journal/page-title-format "EEE, yyyy/MM/dd"}})
ref-journal (db-test/find-journal-by-journal-day @conn 20260517)]
(is (= "Sun, 2026/05/17" (:block/title ref-journal))
"Journal reference is imported as a journal page")
(is (nil? (:block/namespace ref-journal))
"Referenced slash-formatted journal does not keep a namespace attribute")
(is (nil? (db-test/find-page-by-title @conn "Sun, 2026"))
"Journal reference is not split into a parent namespace page")
(is (nil? (db-test/find-page-by-title @conn "05"))
"Journal reference is not split into a child namespace page")))
(deftest-async import-normalizes-existing-random-journal-uuid-and-text-refs
(let [old-journal-uuid (random-uuid)
standard-journal-uuid (common-uuid/gen-uuid :journal-page-uuid 20260127)
title (str "refs " (page-ref/->page-ref old-journal-uuid)
" and " (block-ref/->block-ref old-journal-uuid))
conn (db-test/create-conn-with-blocks
{:pages-and-blocks
[{:page {:build/journal 20260127
:block/uuid old-journal-uuid
:build/keep-uuid? true}
:blocks [{:block/title title}]}]})
file (write-temp-graph-file "pages/trigger-normalize.md" "- trigger normalize\n")]
(p/let [_ (import-files-to-db [file] conn {})
journal (db-test/find-journal-by-journal-day @conn 20260127)
ref-block (db-test/find-block-by-content @conn #"refs")]
(is (= standard-journal-uuid (:block/uuid journal))
"Existing random journal uuid is normalized to the standard journal uuid")
(is (nil? (d/entity @conn [:block/uuid old-journal-uuid]))
"Old journal uuid no longer resolves after normalization")
(is (= (str "refs " (page-ref/->page-ref standard-journal-uuid)
" and " (block-ref/->block-ref standard-journal-uuid))
(:block/title ref-block))
"Text references are rewritten to the standard journal uuid")
(is (= (:db/id journal) (get-in ref-block [:block/page :db/id]))
"Structured block page reference still points to the same journal entity"))))
(deftest-async export-files-with-tag-classes-option
(p/let [file-graph-dir "test/resources/exporter-test-graph"
files (mapv #(path/path-join file-graph-dir %) ["journals/2024_02_07.md" "pages/Interstellar.md"])

View File

@@ -1,4 +1,5 @@
- 2nd instance of block w/ longer ns tag #n1/n2/n3
- property pages with '/' should be valid
key/value:: 1
- block with multi word tag #[[another test]] doesn't get removed by page-ref replacement
key/value:: 1
- block with multi word tag #[[another test]] doesn't get removed by page-ref replacement
- [[Jan 1st, 2026]]

View File

@@ -7,6 +7,7 @@
[logseq.common.util :as common-util]
[logseq.common.util.date-time :as date-time-util]
[logseq.common.util.namespace :as ns-util]
[logseq.common.uuid :as common-uuid]
[logseq.db :as ldb]
[logseq.db.common.entity-plus :as entity-plus]
[logseq.db.common.order :as db-order]
@@ -297,7 +298,7 @@
[db title*
{uuid' :uuid
:keys [tags properties persist-op?
class? today-journal? split-namespace? class-ident-namespace]
class? journal? today-journal? split-namespace? class-ident-namespace]
:or {properties nil
persist-op? true}
:as options}]
@@ -311,7 +312,7 @@
_ (outliner-validate/validate-page-title-no-hashtag title {:node {:block/title title}})
types (cond class?
#{:logseq.class/Tag}
today-journal?
(or journal? today-journal?)
#{:logseq.class/Journal}
(seq tags)
(set (map :db/ident tags))
@@ -375,7 +376,9 @@
{:class? class?
:page-uuid (when (uuid? uuid') uuid')
:skip-existing-page-check? true})
[page parents'] (if (and (text/namespace-page? title) split-namespace?)
[page parents'] (if (and (not (:block/journal-day page))
(text/namespace-page? title)
split-namespace?)
(let [pages (split-namespace-pages db page date-formatter class?)]
[(last pages) (butlast pages)])
[page nil])]
@@ -389,7 +392,10 @@
(doseq [parent parents']
(outliner-validate/validate-page-title-characters (str (:block/title parent)) {:node parent})))
(let [page-uuid (:block/uuid page)
(let [page-uuid (if-let [journal-day (:block/journal-day page)]
(common-uuid/gen-uuid :journal-page-uuid journal-day)
(:block/uuid page))
page (assoc page :block/uuid page-uuid)
page-txs (build-page-tx db properties page (select-keys options [:class? :tags :class-ident-namespace]))
txs (concat
;; transact doesn't support entities

View File

@@ -5,6 +5,7 @@
[logseq.common.util :as common-util]
[logseq.common.util.date-time :as date-time-util]
[logseq.common.util.page-ref :as page-ref]
[logseq.common.uuid :as common-uuid]
[logseq.db :as ldb]
[logseq.db.common.order :as db-order]
[logseq.db.frontend.db :as db-db]
@@ -186,3 +187,20 @@
"Journal title follows configured formatter")
(is (= default-name (:block/name page))
"Journal block/name remains the default formatter, independent of title format")))
(deftest create-slash-formatted-journal-does-not-create-namespace-pages
(let [conn (db-test/create-conn)
_ (d/transact! conn [[:db/add :logseq.class/Journal :logseq.property.journal/title-format "yyyy/MM/dd"]])
[_ page-uuid] (outliner-page/create! conn "May 18th, 2026" {:split-namespace? true
:journal? true})
page (d/entity @conn [:block/uuid page-uuid])]
(is (= "2026/05/18" (:block/title page))
"Journal title follows slash title format")
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260518) (:block/uuid page))
"Journal page has the standard journal uuid")
(is (nil? (ldb/get-page @conn "2026"))
"Journal title is not split into a year namespace page")
(is (nil? (ldb/get-page @conn "05"))
"Journal title is not split into a month namespace page")
(is (nil? (ldb/get-page @conn "18"))
"Journal title is not split into a day namespace page")))

View File

@@ -12,6 +12,7 @@
[electron.ipc :as ipc]
[frontend.components.avatar :as avatar]
[frontend.components.block.breadcrumb-model :as breadcrumb-model]
[frontend.components.block.asset :as block-asset]
[frontend.components.block.comments :as block-comments]
[frontend.components.block.comments-model :as comments-model]
[frontend.components.block.drop :as block-drop]
@@ -518,8 +519,8 @@
(:image-placeholder config)
(if (and (:image-placeholder config) (nil? @src))
(:image-placeholder config)
(let [ext (keyword (or (util/get-file-ext @src)
(util/get-file-ext href)))
(let [asset-block (:asset-block config)
ext (block-asset/link-ext @src href asset-block)
repo (state/get-current-repo)
repo-dir (config/get-repo-dir repo)
share-fn (fn [event]
@@ -560,15 +561,14 @@
title]
util/web-platform?
(let [file-name (str (:block/title (:asset-block config)) "." (name ext))]
(let [file-name (block-asset/link-file-name asset-block ext)]
[:a.asset-ref
{:href @src
:download file-name}
file-name])
(and (util/electron?) (:asset-block config))
(let [asset-block (:asset-block config)
file-name (str (:block/title asset-block) "." (name ext))]
(and (util/electron?) asset-block)
(let [file-name (block-asset/link-file-name asset-block ext)]
[:a.asset-ref
{:on-click (fn [e]
(util/stop e)
@@ -582,7 +582,7 @@
file-fpath (if local-ext-url?
;; Plugin-sourced asset stored under assets/storages/<plugin-id>/...
(path/path-join repo-dir (string/replace ext-url #"^[./]+" ""))
(path/path-join repo-dir (str "assets/" (:block/uuid asset-block) "." (name ext))))]
(path/path-join repo-dir (str "assets/" (:block/uuid asset-block) (when ext (str "." (name ext))))))]
(if remote-ext-url?
(js/window.apis.openExternal ext-url)
(js/window.apis.openPath file-fpath))))}

View File

@@ -0,0 +1,34 @@
(ns frontend.components.block.asset
"Helpers for rendering asset links in block content.
Asset links can point to local files, graph-relative files, remote URLs, or
protocol URLs. These helpers normalize the display-facing parts of an asset
without assuming that the URL itself contains a file extension."
(:require [clojure.string :as string]
[frontend.util :as util]))
(defn- asset-type->keyword
"Coerces `asset-type` from an asset entity into a lowercase keyword.
Returns `nil` when `asset-type` is absent or has an unsupported type."
[asset-type]
(cond
(keyword? asset-type) asset-type
(string? asset-type) (keyword (string/lower-case asset-type))))
(defn link-ext
"Resolves the extension keyword for an asset link.
`src` is the resolved render URL, `href` is the original asset link, and
`asset-block` is the asset entity. The URL-derived extension has priority;
`:logseq.property.asset/type` is used when neither URL exposes an extension."
[src href asset-block]
(or (some-> (util/get-file-ext src) keyword)
(some-> (util/get-file-ext href) keyword)
(asset-type->keyword (:logseq.property.asset/type asset-block))))
(defn link-file-name
"Builds the display file name for `asset-block` using resolved extension `ext`."
[asset-block ext]
(cond-> (str (:block/title asset-block))
ext (str "." (name ext))))

View File

@@ -3,19 +3,36 @@
(:require [logseq.outliner.page :as outliner-page]))
(defn create!
"Create page. Has the following options:
"Creates a page through the outliner page service.
* :uuid - when set, use this uuid instead of generating a new one.
* :class? - when true, adds a :block/tags ':logseq.class/Tag'
* :tags - tag uuids that are added to :block/tags
* :persist-op? - when true, add an update-page op
* :properties - properties to add to the page
TODO: Add other options"
Supported options:
* :uuid - when set, use this uuid instead of generating a new one; ignored
when :journal? or :today-journal? uses a deterministic journal
uuid from :block/journal-day.
* :class? - create the page as a Tag class page.
* :journal? - create the page as a Journal page.
* :today-journal? - mark the create-page tx as today's journal creation.
* :tags - tag uuids or tag entities added to :block/tags.
* :properties - properties to add to the page.
* :split-namespace? - create namespace parent pages for non-journal slash pages.
* :class-ident-namespace - namespace used when creating a class ident.
* :persist-op? - when true, persist the create-page outliner op."
[conn title & {:as options}]
(outliner-page/create! conn title options))
(defn delete!
"Deletes a page. Returns true if able to delete page. If unable to delete,
calls error-handler fn and returns false"
"Deletes a page through the outliner page service.
Returns true when the page can be deleted. If deletion is rejected, calls
:error-handler and returns false.
Supported options:
* :persist-op? - when true, persist the delete-page outliner op.
* :rename? - mark the tx as part of a rename flow.
* :error-handler - callback invoked with {:msg string} on rejection.
* :deleted-by-uuid - user uuid recorded in the delete op metadata.
* :now-ms - timestamp recorded in the delete op metadata."
[conn page-uuid & {:as options}]
(outliner-page/delete! conn page-uuid options))

View File

@@ -0,0 +1,18 @@
(ns frontend.components.block.asset-test
(:require [cljs.test :refer [deftest is testing]]
[frontend.components.block.asset :as block-asset]))
(deftest link-ext-test
(testing "falls back to asset type when the URL has no extension"
(is (= :pdf
(block-asset/link-ext
"zotero://select/library/items/QLUSY2JL"
"zotero://select/library/items/QLUSY2JL"
{:logseq.property.asset/type "pdf"})))))
(deftest link-file-name-test
(testing "uses the resolved extension in the displayed file name"
(is (= "test.pdf"
(block-asset/link-file-name
{:block/title "test"}
:pdf)))))

View File

@@ -189,7 +189,7 @@
(deftest create-journal-page-name-uses-default-formatter-test
(let [conn (db-test/create-conn)]
(d/transact! conn [[:db/add :logseq.class/Journal :logseq.property.journal/title-format "yyyy-MM-dd EEEE"]])
(let [[_ page-uuid] (outliner-page/create! conn "Dec 16th, 2024" {})
(let [[_ page-uuid] (outliner-page/create! conn "Dec 16th, 2024" {:journal? true})
page (d/entity @conn [:block/uuid page-uuid])
journal-day (:block/journal-day page)
expected-title (date-time-util/int->journal-title journal-day "yyyy-MM-dd EEEE")