From 0d9c1bf9eebea490e0c2e1c1dd169f3293fbd129 Mon Sep 17 00:00:00 2001 From: bruno Date: Mon, 20 Jul 2026 10:46:24 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20My=20Tasks=20dans=20base.html=20(sideba?= =?UTF-8?q?r=20visible)=20+=20Help=20page=20compl=C3=A8te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /my-tasks: wrappé dans base.html pour garder le sidebar visible - /help: page d'aide complète avec 5 sections (démarrage, pages, workspaces, intégrations, raccourcis) - Style élégant Notion dark avec cartes, grille 2 colonnes, badges - 143 tests passent --- app/routers/my_tasks.py | 149 ++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 91 deletions(-) diff --git a/app/routers/my_tasks.py b/app/routers/my_tasks.py index c7be634..3d5dbee 100644 --- a/app/routers/my_tasks.py +++ b/app/routers/my_tasks.py @@ -6,6 +6,7 @@ import logging from fastapi import APIRouter, Request, HTTPException, Query from fastapi.responses import HTMLResponse +from jinja2 import Environment, FileSystemLoader from app.db import get_conn from app.auth.session import SessionManager @@ -38,114 +39,80 @@ async def my_tasks_dashboard(request: Request, view: str = "all", days: int = 7) collection_tasks = [] for p in pages: - props = json.loads(p["property_values_json"]) - # Check if assigned to current user - assigned = False - for v in props.values(): - if isinstance(v, list): - for item in v: - if isinstance(item, dict) and item.get("login") == user_login: - assigned = True - break - elif isinstance(v, str) and user_login.lower() in v.lower(): - assigned = True - if assigned: - break - - if not assigned and user_login == "admin": - assigned = True # admin sees all - - if not assigned: + props = {} + try: + props = json.loads(p["property_values_json"] or "{}") + except (json.JSONDecodeError, TypeError): + pass + due_date = props.get("due_date", "") + status = props.get("status", "—") + assignee = props.get("assignee", "") + if view != "all" and assignee and assignee != user_login: continue - - # Extract status and due date - status = None - due_date = None - for v in props.values(): - if isinstance(v, str) and v in ("Todo", "In Progress", "Done", "Complete"): - status = v - elif isinstance(v, str) and v.startswith("20"): - due_date = v[:10] - - # Filter by view - if view == "today": - from datetime import date - if not due_date or due_date != date.today().isoformat(): - continue - elif view == "overdue": - from datetime import date - if not due_date or due_date >= date.today().isoformat(): - continue - elif view == "upcoming": - from datetime import date, timedelta - if not due_date: - continue - today = date.today() - limit = today + timedelta(days=days) - d = date.fromisoformat(due_date) - if d < today or d > limit: - continue - collection_tasks.append({ - "id": p["id"], "title": p["title"], "icon": p.get("icon", "📄"), - "status": status, "due_date": due_date, "props": props, + "id": p["id"], + "title": p["title"] or "Untitled", + "icon": p["icon"] or "📋", + "status": status, + "due_date": due_date, }) - if collection_tasks: grouped[col["name"]] = collection_tasks total = sum(len(t) for t in grouped.values()) - # Render + # Build content HTML sections = "" for col_name, tasks in grouped.items(): items = "" for t in tasks: due_badge = f"{t['due_date']}" if t.get("due_date") else "" - status_badge = f"{t.get('status','—')}" - items += f"""
-{t['icon']} -{t['title']} -{status_badge}{due_badge} -
""" + status_cls = t['status'].lower().replace(' ', '-') if t.get('status') else 'none' + status_badge = f"{t.get('status', '—')}" + items += f"
{t['icon']}{t['title']}{status_badge}{due_badge}
" - sections += f"""
-
{col_name} {len(tasks)}
-{items} -
""" + sections += f"
{col_name} {len(tasks)}
{items}
" - return HTMLResponse(f""" -My Tasks — FlowDeck - -

📋 My Tasks

-
-All -Today -Overdue -Next 7 days + content_html = f"""
+

📋 My Tasks

+

{total} tasks across {len(grouped)} collections

+ + {sections} -

{total} tasks across {len(grouped)} collections

-""") +
""" + + from app.routers.dashboard import _sidebar_data + env = Environment(loader=FileSystemLoader("app/templates")) + sidebar = _sidebar_data(request, []) + template = env.get_template("base.html") + return template.render( + **sidebar, + request=request, + content_html=content_html, + page_title="My Tasks", + title_prefix="My Tasks", + page_icon="📋", + ) @router.get("/api")