0.2.0 — a notebook in your pocket, ready to be hosted #3

Merged
bvandeusen merged 22 commits from dev into main 2026-08-23 16:38:00 -04:00
Showing only changes of commit 229076c82d - Show all commits
+14 -4
View File
@@ -209,12 +209,22 @@ def _assign_note_fields(note: Note, ch: dict) -> None:
async def _apply_note_items(db, note: Note, ch: dict) -> None:
"""Replace the note's checklist items with the client's (items sync inline)."""
if note.kind != "list":
await db.execute(sa_delete(NoteItem).where(NoteItem.note_id == note.id))
return
"""Replace the note's checklist items with the client's (items sync inline).
Applies to ANY note. This used to delete every item when the note wasn't
`kind == "list"`, which was survivable only because nothing could produce a note
holding both a body and items. M13 makes that the normal shape — a checklist is
something a note HAS, not something a note IS — and against that shape the old
guard was a data-loss path: the first sync after adding a checklist to a note
would have wiped it.
Removed ahead of the UI that can create the state, deliberately, so there is no
window in which the two disagree.
"""
items = ch.get("items")
if not isinstance(items, list):
# Absent means "not telling us", not "empty". A client that omits the key
# leaves what the server has; only an explicit [] clears it.
return
await db.execute(sa_delete(NoteItem).where(NoteItem.note_id == note.id))
for pos, it in enumerate(items):