m4.5: lists first-class — create a checklist straight from quick-add
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 6s
CI & Build / Python tests (push) Successful in 9s
CI & Build / Build & push image (push) Successful in 34s

Checklist notes existed (M2) but could only be made by creating a text
note and toggling it in the editor — so they were undiscoverable. Now
the board's quick-add can make one in one shot.

- create endpoint accepts kind + items: POST /api/notes with
  kind:"list" and items:[...] creates a checklist note and its items
  atomically. A list note is non-empty when it has a title or ≥1 item.
- quick-add gets a checklist toggle (checkbox icon): flip it and each
  body line becomes an item on save; placeholder switches to
  "One item per line"; resets to a plain note after close.
- notes store create() accepts kind + items; parse_list_items() helper
  (trims, drops blanks) with a unit test.
- title placeholders now read "Title (optional)" in quick-add too.

Third item of M4.5. Display/editing of checklists was already built in
M2; this closes the creation gap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
2026-07-22 08:26:19 -04:00
co-authored by Claude Opus 4.8
parent 0ae02858f7
commit 80324fba3b
4 changed files with 74 additions and 7 deletions
+8
View File
@@ -8,6 +8,7 @@ from thoughtsync.notes import (
is_empty_note,
normalize_color,
parse_link_titles,
parse_list_items,
rewrite_link_title,
)
@@ -130,6 +131,13 @@ def test_derive_display_title_caps_length():
assert derive_display_title(long, "body") == "x" * 200
def test_parse_list_items():
assert parse_list_items(["milk", " eggs ", "", " ", "bread"]) == ["milk", "eggs", "bread"]
assert parse_list_items("not a list") == []
assert parse_list_items(None) == []
assert parse_list_items([1, "x", None, {"a": 1}]) == ["x"]
def test_escape_like():
# LIKE wildcards in user input must be neutralized so they match literally.
assert _escape_like("100%") == "100\\%"