Fase B7: CalDAV/CardDAV sync with Nextcloud, and a Calendar view type
- New built-in classes Event and Contact (schema 65.37), plus a Calendar View view type alongside table/list/gallery, backed by a new fixed month-grid calendar-view component in components/views.cljs reusing the existing scheduled/deadline properties. - New worker/handler/caldav.cljs: a deliberately-scoped CalDAV (VEVENT/VTODO) + CardDAV (VCARD) client against a single Nextcloud calendar/addressbook collection, with its own minimal iCalendar/vCard encoder-decoder and namespace-agnostic multistatus XML extraction (no external ical/rrule/xml dependency exists in this project). - RRULE <-> :logseq.property.repeat/* translation covers only the `plus` (advance-from-scheduled) repeat mode with a bare FREQ(;INTERVAL) rule -- dotted-plus/double-plus and anything with BYDAY/COUNT/UNTIL are left untranslated on purpose rather than mistranslated. - Credentials live in the platform keychain (save-secret-text!), never in the graph. Sync runs Node-only, every 15 minutes per open repo, started/stopped alongside the repo's lifecycle in db_core.cljs. Conflicts are last-write-wins via ETag: a 412 on push is skipped and retried after the next pull refreshes the stored ETag.
This commit is contained in:
19
deps/db/src/logseq/db/frontend/class.cljs
vendored
19
deps/db/src/logseq/db/frontend/class.cljs
vendored
@@ -115,6 +115,25 @@
|
||||
{:title "Area"
|
||||
:properties {:logseq.property.class/extends :logseq.class/Page}}
|
||||
|
||||
;; :logseq.property/scheduled and :logseq.property/deadline (the actual
|
||||
;; event start/end) are pre-existing baseline properties, not declared
|
||||
;; here in :schema :properties -- a migrated-in class can only resolve
|
||||
;; :schema :properties against properties added in that SAME migration
|
||||
;; step (see `build-initial-classes*`), so a page can still be tagged
|
||||
;; Event and given scheduled/deadline like any other public property.
|
||||
:logseq.class/Event
|
||||
{:title "Event"
|
||||
:properties {:logseq.property.class/extends :logseq.class/Page
|
||||
:logseq.property/icon {:type :tabler-icon :id "calendar-event"}}
|
||||
:schema {:properties [:logseq.property.event/location]}}
|
||||
|
||||
:logseq.class/Contact
|
||||
{:title "Contact"
|
||||
:properties {:logseq.property.class/extends :logseq.class/Page
|
||||
:logseq.property/icon {:type :tabler-icon :id "user"}}
|
||||
:schema {:properties [:logseq.property.contact/email :logseq.property.contact/phone
|
||||
:logseq.property.contact/organization]}}
|
||||
|
||||
;; TODO: Add more classes such as :book, :paper, :movie, :music)
|
||||
)))
|
||||
|
||||
|
||||
33
deps/db/src/logseq/db/frontend/property.cljs
vendored
33
deps/db/src/logseq/db/frontend/property.cljs
vendored
@@ -422,6 +422,36 @@
|
||||
|
||||
;; TODO: Add more props :Estimate, :Cycle, :Project
|
||||
|
||||
:logseq.property.event/location {:title "Location"
|
||||
:schema {:type :string
|
||||
:public? true}
|
||||
:queryable? true}
|
||||
:logseq.property.contact/email {:title "Email"
|
||||
:schema {:type :string
|
||||
:public? true}
|
||||
:queryable? true}
|
||||
:logseq.property.contact/phone {:title "Phone"
|
||||
:schema {:type :string
|
||||
:public? true}
|
||||
:queryable? true}
|
||||
:logseq.property.contact/organization {:title "Organization"
|
||||
:schema {:type :string
|
||||
:public? true}
|
||||
:queryable? true}
|
||||
;; CalDAV/CardDAV sync bookkeeping, not user-facing
|
||||
:logseq.property.caldav/uid {:title "CalDAV UID"
|
||||
:schema {:type :string
|
||||
:hide? true
|
||||
:public? false}}
|
||||
:logseq.property.caldav/href {:title "CalDAV Href"
|
||||
:schema {:type :string
|
||||
:hide? true
|
||||
:public? false}}
|
||||
:logseq.property.caldav/etag {:title "CalDAV ETag"
|
||||
:schema {:type :string
|
||||
:hide? true
|
||||
:public? false}}
|
||||
|
||||
:logseq.property/icon {:title "Icon"
|
||||
:schema {:type :map}}
|
||||
:logseq.property/publishing-public? {:title "Publishing Public?"
|
||||
@@ -455,7 +485,8 @@
|
||||
:icon {:type :tabler-icon :id icon}})
|
||||
[[:logseq.property.view/type.table "Table View" "table"]
|
||||
[:logseq.property.view/type.list "List View" "list"]
|
||||
[:logseq.property.view/type.gallery "Gallery View" "layout-grid"]])
|
||||
[:logseq.property.view/type.gallery "Gallery View" "layout-grid"]
|
||||
[:logseq.property.view/type.calendar "Calendar View" "calendar"]])
|
||||
:properties {:logseq.property/default-value :logseq.property.view/type.table}
|
||||
:queryable? true}
|
||||
|
||||
|
||||
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)
|
||||
[(parse-schema-version x) (parse-schema-version y)])))
|
||||
|
||||
(def version (parse-schema-version "65.36"))
|
||||
(def version (parse-schema-version "65.37"))
|
||||
|
||||
(defn major-version
|
||||
"Return a number.
|
||||
|
||||
12
deps/db/test/logseq/db/frontend/class_test.cljs
vendored
12
deps/db/test/logseq/db/frontend/class_test.cljs
vendored
@@ -16,6 +16,18 @@
|
||||
(is (not (contains? db-class/private-tags :logseq.class/Project)))
|
||||
(is (not (contains? db-class/private-tags :logseq.class/Area)))))
|
||||
|
||||
(deftest event-and-contact-are-built-in-page-classes
|
||||
(testing "Event and Contact are registered as built-in classes that behave like pages"
|
||||
(is (contains? db-class/built-in-classes :logseq.class/Event))
|
||||
(is (contains? db-class/built-in-classes :logseq.class/Contact))
|
||||
(is (contains? db-class/page-children-classes :logseq.class/Event))
|
||||
(is (contains? db-class/page-children-classes :logseq.class/Contact))
|
||||
(is (not (contains? db-class/private-tags :logseq.class/Event)))
|
||||
(is (not (contains? db-class/private-tags :logseq.class/Contact))))
|
||||
(testing "Event's schema properties only reference properties migrated in the same step"
|
||||
(is (= [:logseq.property.event/location]
|
||||
(get-in db-class/built-in-classes [:logseq.class/Event :schema :properties])))))
|
||||
|
||||
(deftest get-class-objects-dedupes-inherited-tags-test
|
||||
(let [conn (db-test/create-conn-with-blocks
|
||||
{:classes {:Parent {:block/title "Parent"}
|
||||
|
||||
Reference in New Issue
Block a user