feat(notes): ajout de liens nommés (label + url) sur les notes

Backend :
- Migration 006 : colonne urls JSONB nullable sur notes.items
- Modèle NoteItem : champ urls list[dict]
- Schémas : NoteUrl (label + url avec validation http/https),
  NoteCreate/NoteUpdate/NoteResponse exposent urls

Frontend :
- api/notes.ts : interface NoteUrl + champ urls sur Note/NoteCreate
- NoteForm : section "Liens" avec ajout (libellé + URL), suppression,
  validation http/https, confirmation par Enter
- NotesPage : badge compteur liens dans metaLine (semi/collapsed),
  section liens cliquables dans le mode expanded

v0.5.13

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 09:47:49 +02:00
co-authored by Claude Sonnet 4.6
parent b084905226
commit 031708ad8f
7 changed files with 185 additions and 4 deletions
@@ -0,0 +1,27 @@
"""006 - ajout colonne urls (JSONB) sur notes.items
Revision ID: 006
Revises: 005
Create Date: 2026-05-30
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSONB
revision = '006'
down_revision = '005'
branch_labels = None
depends_on = None
def upgrade():
op.add_column(
'items',
sa.Column('urls', JSONB, nullable=True),
schema='notes',
)
def downgrade():
op.drop_column('items', 'urls', schema='notes')
+1
View File
@@ -18,6 +18,7 @@ class NoteItem(Base):
tags: Mapped[list[str]] = mapped_column(ARRAY(String(50)), server_default=text("'{}'::varchar[]"))
gps_lat: Mapped[Decimal | None] = mapped_column(Numeric(10, 7))
gps_lon: Mapped[Decimal | None] = mapped_column(Numeric(10, 7))
urls: Mapped[list[dict] | None] = mapped_column(JSONB, nullable=True)
metadata_: Mapped[dict | None] = mapped_column("metadata", JSONB)
created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=text("now()"))
owner_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
+16 -1
View File
@@ -1,6 +1,18 @@
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict
from pydantic import BaseModel, ConfigDict, HttpUrl, field_validator
class NoteUrl(BaseModel):
label: str
url: str
@field_validator('url')
@classmethod
def validate_url(cls, v: str) -> str:
if not v.startswith(('http://', 'https://')):
raise ValueError('URL doit commencer par http:// ou https://')
return v
class AttachmentResponse(BaseModel):
@@ -20,6 +32,7 @@ class NoteCreate(BaseModel):
tags: list[str] = []
gps_lat: float | None = None
gps_lon: float | None = None
urls: list[NoteUrl] = []
class NoteUpdate(BaseModel):
@@ -29,6 +42,7 @@ class NoteUpdate(BaseModel):
tags: list[str] | None = None
gps_lat: float | None = None
gps_lon: float | None = None
urls: list[NoteUrl] | None = None
class NoteResponse(BaseModel):
@@ -40,5 +54,6 @@ class NoteResponse(BaseModel):
tags: list[str]
gps_lat: float | None
gps_lon: float | None
urls: list[NoteUrl] = []
created_at: datetime
attachments: list[AttachmentResponse]