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:
2026-08-26 21:11:00 +02:00
parent dadeca7165
commit 0158430489
12 changed files with 896 additions and 3 deletions

View File

@@ -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"}