m4.5: titles optional — every note gets an auto display name
Capture starts in the body, so forcing a title feels odd and body-only notes had no name — which made them unlinkable. Fix both: persist a display_title = explicit title if set, else the note's first non-empty body line (deterministic, no AI). The title field stays optional. - migration 0012: notes.display_title (NOT NULL, best-effort backfill; the app recomputes precisely on next save) - derive_display_title() helper, set on create + update - drive the /titles index, backlinks, graph edges + node labels, and [[wiki-link]] resolution off display_title so body-only notes are nameable, findable (command palette / [[ autocomplete), and linkable - rename-repoint generalized: inbound [[Old Name]] links now survive a name change via the first body line too, not just an explicit title - unit tests for the derivation (explicit wins, first non-empty line, blank/empty, length cap) - frontend: display_title on the Note type; title field placeholder now reads "Title (optional)" First item of M4.5 (frictionless input & recall); unblocks the linking work. Card rendering unchanged (no first-line duplication). 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:
@@ -0,0 +1,36 @@
|
||||
"""notes.display_title
|
||||
|
||||
Revision ID: 0012
|
||||
Revises: 0011
|
||||
Create Date: 2026-07-22
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0012"
|
||||
down_revision = "0011"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# The note's display NAME: explicit title if set, else the first body line.
|
||||
op.add_column("notes", sa.Column("display_title", sa.Text(), nullable=False, server_default=""))
|
||||
# Best-effort backfill (kept intentionally simple + unambiguous — CI has no
|
||||
# Postgres lane, so this only runs on a real deploy). The app recomputes the
|
||||
# precise value via derive_display_title on the next save (which additionally
|
||||
# skips leading blank lines). Capped at 200 chars.
|
||||
op.execute(
|
||||
r"""
|
||||
UPDATE notes SET display_title = LEFT(btrim(
|
||||
CASE
|
||||
WHEN title IS NOT NULL AND btrim(title) <> '' THEN title
|
||||
ELSE split_part(body, E'\n', 1)
|
||||
END
|
||||
), 200)
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("notes", "display_title")
|
||||
Reference in New Issue
Block a user