Files
chihlasm fafdaa50a5 Add tree organization system with categories, tags, and folders
Features:
- Categories: Global and team-specific tree categorization (admin-managed)
- Tags: Flexible tree tagging with autocomplete (author + admin)
- User folders: Personal tree collections with subfolder support
  - Hierarchical structure (max 3 levels deep)
  - Right-click context menu for folder management
  - Cascade delete for subfolders
- Filter trees by category, tags, and folder in library view

Backend:
- New models: Category, Tag, UserFolder with relationships
- New API endpoints for categories, tags, and folders
- Tree organization migrations (005, 006)

Frontend:
- FolderSidebar with hierarchical folder tree
- FolderEditModal for create/edit with color picker
- AddToFolderMenu for quick tree organization
- TagInput with autocomplete and TagBadges display
- Updated TreeMetadataForm and TreeLibraryPage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 01:31:13 -05:00

63 lines
1.6 KiB
Python

from datetime import datetime
from typing import Optional
from uuid import UUID
from pydantic import BaseModel, Field
import re
# Valid hex color pattern
HEX_COLOR_PATTERN = r'^#[0-9A-Fa-f]{6}$'
class FolderBase(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
color: str = Field("#6366f1", pattern=HEX_COLOR_PATTERN)
icon: str = Field("folder", max_length=50)
class FolderCreate(FolderBase):
parent_id: Optional[UUID] = Field(None, description="Parent folder ID for creating subfolders")
class FolderUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
color: Optional[str] = Field(None, pattern=HEX_COLOR_PATTERN)
icon: Optional[str] = Field(None, max_length=50)
display_order: Optional[int] = None
parent_id: Optional[UUID] = Field(None, description="Parent folder ID to move folder")
class FolderResponse(FolderBase):
id: UUID
parent_id: Optional[UUID] = None
display_order: int
tree_count: int = 0 # Computed field
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class FolderListResponse(BaseModel):
id: UUID
name: str
color: str
icon: str
parent_id: Optional[UUID] = None
display_order: int
tree_count: int = 0
class Config:
from_attributes = True
class FolderReorderRequest(BaseModel):
"""Request body for reordering folders."""
folder_ids: list[UUID] = Field(..., min_length=1, description="Folder IDs in desired order")
class FolderTreeRequest(BaseModel):
"""Request body for adding a tree to a folder."""
tree_id: UUID