Lot 4/4 de l'A28 (god files) : l'ancien app/routers/board.py (2 101 lignes, 53 routes) devient le package `app/routers/board/` : - 12 modules de routes : pages 271 L (7 r.), page_api 229 (5), board_views 223 (8), page_ops 176 (3), sharing 175 (10), synced 144 (8), page_media 122 (4), import_ 85 (2), wiki 76 (2), library 66 (1), embed 64 (2), sync 51 (1) - _common.py (878 L) : 23 helpers dont 4 async + les 4 constantes (STATUS_COLORS, STATUS_LABELS, AI_KEYWORD_COLORS, _REPO_REF_RE) - __init__.py : __all__ complet — importateurs inchangés (api.py ×4 top-level, webhooks top-level, dashboard ×5 lazy, tests ×4) Preuve contractuelle : docs/openapi-v2.json régénéré = IDENTIQUE byte-à-byte (509 chemins, ordre préservé). Pièges rattrapés : - constantes d'état oubliées dans _common à la 1ʳᵉ passe (F821 + ImportError au chargement) → ré-insérées avec les valeurs exactes - docstring du header copié → F404 → slice [1:21] - helpers `async def` non détectés par `def ` seul A28 TERMINÉ en 4 lots : api_v2 (7.29.0), dashboard (7.30.0), collections (7.31.0), board (7.32.0) — 0 changement d'URL sur les 4. suite **1091/1091** · ruff OK · OpenAPI 509 identique · docs à jour
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
"""FlowDeck — Board : library.
|
|
|
|
Découpe A28 de l'ancien app/routers/board.py (2 101 lignes, 53 routes) — un module par concern, contrat inchangé.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Query, Request
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
from app.db import get_conn
|
|
|
|
from ._common import _sidebar_data
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(tags=["board"], prefix="/board")
|
|
|
|
|
|
|
|
|
|
# ═══════════ Library page ═══════════
|
|
|
|
@router.get("/library", response_class=HTMLResponse)
|
|
def library_page(request: Request, owner: str = Query(default=""), repo: str = Query(default="")):
|
|
"""Library page avec onglets Recents, Favorites, Shared, Private — scopé au workspace."""
|
|
from app.templating import ENV
|
|
env = ENV
|
|
sidebar = _sidebar_data(request, owner, repo)
|
|
# Load all pages for the workspace from DB
|
|
ws_key = f"{owner}/{repo}" if owner and repo else ""
|
|
with get_conn() as conn:
|
|
if ws_key:
|
|
rows = conn.execute(
|
|
"SELECT id, title, workspace, updated_at FROM pages "
|
|
"WHERE workspace=? AND collection_row_id IS NULL ORDER BY updated_at DESC",
|
|
(ws_key,),
|
|
).fetchall()
|
|
else:
|
|
rows = conn.execute(
|
|
"SELECT id, title, workspace, updated_at FROM pages "
|
|
"WHERE collection_row_id IS NULL ORDER BY updated_at DESC",
|
|
).fetchall()
|
|
all_pages = []
|
|
for r in rows:
|
|
page = dict(r)
|
|
all_pages.append({
|
|
"id": f"page/{page['id']}",
|
|
"name": page["title"] or "Untitled",
|
|
"icon": "📄",
|
|
"url": f"/pages/{page['id']}",
|
|
"created_by": "You",
|
|
"source": page.get("workspace") or "Private",
|
|
"last_edited": page.get("updated_at", "now"),
|
|
"last_visited": page.get("updated_at", "now"),
|
|
})
|
|
sidebar["recent_pages"] = all_pages
|
|
sidebar["favorite_pages"] = []
|
|
sidebar["private_pages"] = [p for p in all_pages if p.get("source") == "🔒 Private"]
|
|
sidebar["shared_pages"] = []
|
|
sidebar["shared_made_pages"] = []
|
|
sidebar["shared_received_pages"] = []
|
|
template = env.get_template("library.html")
|
|
return template.render(**sidebar)
|
|
|
|
# ═══════════ Favorites API ═══════════
|