DRY refactoring pass: shared mixins, route helpers, composables, CSS

Backend:
- models/base.py: TimestampMixin + CreatedAtMixin; applied to all 10+ models
- routes/utils.py: not_found() + parse_iso_date() helpers; used across all route files
- routes/milestones.py: _milestone_dict() helper replaces 5 repeated to_dict + progress blocks

Frontend:
- 5 new composables: useAutoSave, useEditorGuards, useTagSuggestions,
  useFloatingAssist, useListKeyboardNavigation
- ConfirmDialog.vue: reusable confirm modal replacing inline <teleport> blocks
- editor-shared.css: sidebar CSS consolidated from both editor views
- viewer-shared.css: context-bar/breadcrumb CSS consolidated from both viewer views
- NoteEditorView + TaskEditorView: ~120 lines each replaced with composable calls;
  duplicate scoped sidebar CSS removed
- NotesListView + TasksListView: inline keyboard-nav replaced with composable
- NoteViewerView + TaskViewerView: duplicate context-bar CSS removed

No behaviour changes. Net: -634 lines, +237 lines across 31 files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 15:26:34 -05:00
parent 48f070f773
commit 16ecd6bbeb
32 changed files with 563 additions and 634 deletions
+4 -11
View File
@@ -1,11 +1,12 @@
import enum
from datetime import date, datetime, timezone
from datetime import date
from sqlalchemy import Date, DateTime, ForeignKey, Index, Integer, Text
from sqlalchemy import Date, ForeignKey, Index, Integer, Text
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import Mapped, mapped_column
from fabledassistant.models import Base
from fabledassistant.models.base import TimestampMixin
class TaskStatus(str, enum.Enum):
@@ -21,7 +22,7 @@ class TaskPriority(str, enum.Enum):
high = "high"
class Note(Base):
class Note(Base, TimestampMixin):
__tablename__ = "notes"
id: Mapped[int] = mapped_column(primary_key=True)
@@ -43,14 +44,6 @@ class Note(Base):
status: Mapped[str | None] = mapped_column(Text, nullable=True)
priority: Mapped[str | None] = mapped_column(Text, nullable=True)
due_date: Mapped[date | None] = mapped_column(Date, nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc),
)
__table_args__ = (
Index("ix_notes_tags", "tags", postgresql_using="gin"),