"""FlowDeck — Dashboard: liste des projets Gitea + sidebar data.""" from __future__ import annotations import logging from fastapi import APIRouter, Request, Query from fastapi.responses import HTMLResponse from app.services.gitea_client import gitea from app.auth.session import SessionManager from app.db import get_conn logger = logging.getLogger(__name__) router = APIRouter(tags=["dashboard"]) def _sidebar_data(request: Request, repos: list[dict]) -> dict: user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) ws = user.get("login", "Bruno") if user else "Bruno" initial = ws[0].upper() if ws else "B" recent_pages = [] for repo in repos[:10]: full_name = repo.get("full_name", "") recent_pages.append({ "id": full_name, "name": repo.get("name", full_name), "icon": "📁", "url": f"/board/{full_name}", "active": False, "indent": 0, "depth": 0, "has_children": False, "children": [], }) return { "workspace_name": ws, "workspace_initial": initial, "current_page": "Dashboard", "last_edited": "now", "recent_pages": recent_pages, "private_pages": [], "favorite_pages": [], "user": user, "workspace_key": "", } @router.get("/trash", response_class=HTMLResponse) async def trash_page(request: Request, owner: str = Query(default=""), repo: str = Query(default="")): """Trash page — scoped to workspace if owner/repo provided.""" from jinja2 import Environment, FileSystemLoader from app.routers.board import _sidebar_data as board_sidebar env = Environment(loader=FileSystemLoader("app/templates")) sidebar = board_sidebar(request, owner, repo) with get_conn() as conn: ws_key = f"{owner}/{repo}" if owner and repo else "" # Pages are soft-deleted via parent_section='Trash' if ws_key: rows = conn.execute( "SELECT id, title, workspace FROM pages WHERE parent_section='Trash' AND workspace=? ORDER BY updated_at DESC", (ws_key,), ).fetchall() else: rows = conn.execute( "SELECT id, title, workspace FROM pages WHERE parent_section='Trash' ORDER BY updated_at DESC", ).fetchall() sidebar["trash_items"] = [{"id": r["id"], "name": r["title"] or "Untitled", "workspace": r["workspace"]} for r in rows] template = env.get_template("trash.html") return template.render(**sidebar) @router.get("/library", response_class=HTMLResponse) async def library_page(request: Request, owner: str = Query(default=""), repo: str = Query(default="")): """Library page avec onglets Recents, Favorites, Shared, Private — scopé au workspace. La sidebar garde exactement la même arborescence que dans le workspace. Seul le contenu principal change pour afficher les pages triées par catégorie. """ from jinja2 import Environment, FileSystemLoader from app.routers.board import _sidebar_data as board_sidebar env = Environment(loader=FileSystemLoader("app/templates")) sidebar = board_sidebar(request, owner, repo) # Sidebar intacte, inchangée ws_key = f"{owner}/{repo}" if owner and repo else "" with get_conn() as conn: base_query = ( "SELECT id, title, workspace, parent_section, updated_at FROM pages " "WHERE parent_section != 'Trash'" ) params = [] if ws_key: base_query += " AND workspace=?" params.append(ws_key) base_query += " ORDER BY updated_at DESC" rows = conn.execute(base_query, params).fetchall() def to_page(r): r = dict(r) return { "id": f"page/{r['id']}", "name": r["title"] or "Untitled", "icon": "📄", "url": f"/pages/{r['id']}", "created_by": "You", "source": r.get("workspace") or "🔒 Private", "last_edited": r.get("updated_at", "now"), "last_visited": r.get("updated_at", "now"), } all_pages = [to_page(r) for r in rows] # Load favorites from DB for Library user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) uid = user["id"] if user and user.get("id") else 1 with get_conn() as conn: fav_rows = conn.execute( "SELECT p.id, p.title, p.workspace, p.updated_at FROM favorites f " "JOIN pages p ON p.id = f.page_id " "WHERE f.user_id=? ORDER BY f.position", (uid,) ).fetchall() lib_favs = [] for r in fav_rows: r = dict(r) lib_favs.append({ "id": f"page/{r['id']}", "name": r["title"] or "Untitled", "icon": "📄", "url": f"/pages/{r['id']}", "created_by": "You", "source": r.get("workspace") or "🔒 Private", "last_edited": r.get("updated_at", "now"), "last_visited": r.get("updated_at", "now"), }) # Catégoriser par parent_section — sidebar data intacte sidebar["lib_recent"] = all_pages sidebar["lib_favorites"] = lib_favs sidebar["lib_shared"] = [] sidebar["lib_private"] = [p for p in all_pages if p.get("source") == "🔒 Private"] sidebar["lib_has_favorites"] = len(lib_favs) > 0 sidebar["lib_has_shared"] = False template = env.get_template("library.html") return template.render(**sidebar) @router.get("/pages/{page_id}", response_class=HTMLResponse) async def view_page_root(request: Request, page_id: int): """Render a Markdown page at root level with workspace context.""" from jinja2 import Environment, FileSystemLoader from app.routers.board import _sidebar_data as board_sidebar env = Environment(loader=FileSystemLoader("app/templates")) with get_conn() as conn: row = conn.execute("SELECT * FROM pages WHERE id=?", (page_id,)).fetchone() if not row: return HTMLResponse("