feat: badge emoji partagé (noir & blanc) dans l'arborescence + sidebar «Par moi» inclut is_shared
- board/dashboard: helper _load_shared_sidebar_pages intégrant les pages marquées is_shared directement - _workspace_tree_macro: badge 👥 N&B sur les fichiers partagés du tree du sidebar - local_workspace: badge 👥 en noir & blanc - static/css/app.css: style .page-shared-badge
This commit is contained in:
+67
-50
@@ -175,7 +175,9 @@ def _load_workspace_pages(ws_cookie: str) -> list:
|
||||
ws_id = int(ws_cookie)
|
||||
with get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT id, title, parent_section, content_format FROM pages WHERE workspace_id=? AND parent_id IS NULL AND deleted_at IS NULL ORDER BY created_at DESC",
|
||||
"SELECT id, title, parent_section, content_format, "
|
||||
"is_shared, share_mode, COALESCE(published,0) AS published "
|
||||
"FROM pages WHERE workspace_id=? AND parent_id IS NULL AND deleted_at IS NULL ORDER BY created_at DESC",
|
||||
(ws_id,),
|
||||
).fetchall()
|
||||
items = []
|
||||
@@ -183,11 +185,13 @@ def _load_workspace_pages(ws_cookie: str) -> list:
|
||||
is_folder = r["parent_section"] == "Workspace"
|
||||
title = r["title"] or "Untitled"
|
||||
sub_children = _load_children(r["id"])
|
||||
is_shared = bool(r["is_shared"] or r["share_mode"] != "private" or r["published"])
|
||||
items.append({
|
||||
"db_id": r["id"], "name": title,
|
||||
"id": f"page/{r['id']}",
|
||||
"icon": "📁" if is_folder else _file_icon(title, r["content_format"]),
|
||||
"is_folder": is_folder,
|
||||
"is_shared": is_shared,
|
||||
"child_count": len(sub_children),
|
||||
"children": sub_children,
|
||||
})
|
||||
@@ -200,7 +204,9 @@ def _load_children(parent_id: int) -> list:
|
||||
"""Recursively load children of a page."""
|
||||
with get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT id, title, parent_section, content_format FROM pages WHERE parent_id=? AND deleted_at IS NULL ORDER BY created_at",
|
||||
"SELECT id, title, parent_section, content_format, "
|
||||
"is_shared, share_mode, COALESCE(published,0) AS published "
|
||||
"FROM pages WHERE parent_id=? AND deleted_at IS NULL ORDER BY created_at",
|
||||
(parent_id,),
|
||||
).fetchall()
|
||||
children = []
|
||||
@@ -208,11 +214,13 @@ def _load_children(parent_id: int) -> list:
|
||||
is_folder = r["parent_section"] == "Workspace"
|
||||
title = r["title"] or "Untitled"
|
||||
sub_children = _load_children(r["id"])
|
||||
is_shared = bool(r["is_shared"] or r["share_mode"] != "private" or r["published"])
|
||||
children.append({
|
||||
"db_id": r["id"], "name": title,
|
||||
"id": f"page/{r['id']}",
|
||||
"icon": "📁" if is_folder else _file_icon(title, r["content_format"]),
|
||||
"is_folder": is_folder,
|
||||
"is_shared": is_shared,
|
||||
"child_count": len(sub_children),
|
||||
"children": sub_children,
|
||||
})
|
||||
@@ -235,6 +243,61 @@ def _local_workspaces_for_user(user: dict | None, workspace_id: int = 0) -> list
|
||||
return []
|
||||
|
||||
|
||||
def _load_shared_sidebar_pages(user_id: int) -> tuple[list, list, list, list]:
|
||||
"""Shared / received / published pages for the sidebar (reused by dashboard)."""
|
||||
with get_conn() as conn:
|
||||
made_nominal = conn.execute(
|
||||
"SELECT DISTINCT p.id, p.title, p.workspace, p.updated_at FROM page_shares s "
|
||||
"JOIN pages p ON p.id=s.page_id "
|
||||
"WHERE s.created_by=? AND p.deleted_at IS NULL",
|
||||
(user_id,),
|
||||
).fetchall()
|
||||
made_link = conn.execute(
|
||||
"SELECT id, title, workspace, updated_at FROM pages "
|
||||
"WHERE share_mode='anyone' AND published=0 AND deleted_at IS NULL"
|
||||
).fetchall()
|
||||
made_flag = conn.execute(
|
||||
"SELECT id, title, workspace, updated_at FROM pages "
|
||||
"WHERE (is_shared=1 OR share_mode != 'private') AND COALESCE(published,0)=0 AND deleted_at IS NULL"
|
||||
).fetchall()
|
||||
published_rows = conn.execute(
|
||||
"SELECT id, title, workspace, updated_at FROM pages "
|
||||
"WHERE published=1 AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT 20"
|
||||
).fetchall()
|
||||
received_rows = conn.execute(
|
||||
"SELECT DISTINCT p.id, p.title, p.workspace, p.updated_at FROM page_shares s "
|
||||
"JOIN pages p ON p.id=s.page_id "
|
||||
"WHERE s.shared_with_user_id=? AND p.deleted_at IS NULL",
|
||||
(user_id,),
|
||||
).fetchall()
|
||||
|
||||
def _entry(r, icon):
|
||||
return {
|
||||
"id": f"page/{r['id']}",
|
||||
"db_id": r["id"],
|
||||
"name": r["title"] or "New page",
|
||||
"icon": icon,
|
||||
"url": f"/pages/{r['id']}",
|
||||
"active": False,
|
||||
"indent": 0,
|
||||
"depth": 0,
|
||||
"has_children": False,
|
||||
"children": [],
|
||||
}
|
||||
|
||||
made_map = {}
|
||||
for r in (*made_nominal, *made_link, *made_flag):
|
||||
made_map.setdefault(r["id"], r)
|
||||
made_sorted = sorted(made_map.values(), key=lambda r: r["updated_at"] or "", reverse=True)[:20]
|
||||
shared_made = [_entry(r, "link") for r in made_sorted]
|
||||
received_sorted = [r for r in received_rows if r["id"] not in made_map]
|
||||
received_sorted = sorted(received_sorted, key=lambda r: r["updated_at"] or "", reverse=True)[:20]
|
||||
shared_received = [_entry(r, "users") for r in received_sorted]
|
||||
published = [_entry(r, "globe") for r in published_rows]
|
||||
shared_all = [_entry(r, "link") for r in made_sorted]
|
||||
return shared_made, shared_received, published, shared_all
|
||||
|
||||
|
||||
def _sidebar_data(request: Request, owner: str = "", repo: str = "") -> dict:
|
||||
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
|
||||
ws_name = user.get("login", "Bruno") if user else "Bruno"
|
||||
@@ -338,54 +401,8 @@ def _sidebar_data(request: Request, owner: str = "", repo: str = "") -> dict:
|
||||
"children": [],
|
||||
})
|
||||
|
||||
# Load shared pages: made (page_shares created by me + link-mode pages) and
|
||||
# received (page_shares toward me), plus published pages.
|
||||
with get_conn() as conn:
|
||||
made_nominal = conn.execute(
|
||||
"SELECT DISTINCT p.id, p.title, p.workspace, p.updated_at FROM page_shares s "
|
||||
"JOIN pages p ON p.id=s.page_id "
|
||||
"WHERE s.created_by=? AND p.deleted_at IS NULL",
|
||||
(uid,),
|
||||
).fetchall()
|
||||
made_link = conn.execute(
|
||||
"SELECT id, title, workspace, updated_at FROM pages "
|
||||
"WHERE share_mode='anyone' AND published=0 AND deleted_at IS NULL"
|
||||
).fetchall()
|
||||
published_rows = conn.execute(
|
||||
"SELECT id, title, workspace, updated_at FROM pages "
|
||||
"WHERE published=1 AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT 20"
|
||||
).fetchall()
|
||||
received_rows = conn.execute(
|
||||
"SELECT DISTINCT p.id, p.title, p.workspace, p.updated_at FROM page_shares s "
|
||||
"JOIN pages p ON p.id=s.page_id "
|
||||
"WHERE s.shared_with_user_id=? AND p.deleted_at IS NULL",
|
||||
(uid,),
|
||||
).fetchall()
|
||||
|
||||
def _shared_entry(r, icon):
|
||||
return {
|
||||
"id": f"page/{r['id']}",
|
||||
"db_id": r["id"],
|
||||
"name": r["title"] or "New page",
|
||||
"icon": icon,
|
||||
"url": f"/pages/{r['id']}",
|
||||
"active": False,
|
||||
"indent": 0,
|
||||
"depth": 0,
|
||||
"has_children": False,
|
||||
"children": [],
|
||||
}
|
||||
|
||||
made_map = {}
|
||||
for r in (*made_nominal, *made_link):
|
||||
made_map.setdefault(r["id"], r)
|
||||
made_sorted = sorted(made_map.values(), key=lambda r: r["updated_at"] or "", reverse=True)[:20]
|
||||
shared_made_pages = [_shared_entry(r, "link") for r in made_sorted]
|
||||
received_sorted = [r for r in received_rows if r["id"] not in made_map]
|
||||
received_sorted = sorted(received_sorted, key=lambda r: r["updated_at"] or "", reverse=True)[:20]
|
||||
shared_received_pages = [_shared_entry(r, "users") for r in received_sorted]
|
||||
published_pages = [_shared_entry(r, "globe") for r in published_rows]
|
||||
shared_pages = [_shared_entry(r, "link") for r in made_sorted]
|
||||
# Load shared pages
|
||||
shared_made_pages, shared_received_pages, published_pages, shared_pages = _load_shared_sidebar_pages(uid)
|
||||
|
||||
# Auth method & OAuth badge data
|
||||
auth_method = "local"
|
||||
|
||||
@@ -208,6 +208,15 @@ def _sidebar_data(request: Request, repos: list[dict], include_workspace: bool =
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Shared / received / published pages for the sidebar (Par moi / Avec moi)
|
||||
shared_made_pages = []
|
||||
shared_received_pages = []
|
||||
published_pages = []
|
||||
shared_pages = []
|
||||
if user and user.get("id"):
|
||||
from app.routers.board import _load_shared_sidebar_pages
|
||||
shared_made_pages, shared_received_pages, published_pages, shared_pages = _load_shared_sidebar_pages(user["id"])
|
||||
|
||||
return {
|
||||
"workspace_name": ws, "workspace_initial": initial,
|
||||
"active_ws_name": active_ws_name,
|
||||
@@ -221,10 +230,10 @@ def _sidebar_data(request: Request, repos: list[dict], include_workspace: bool =
|
||||
"recent_pages": recent_pages,
|
||||
"private_pages": private_pages,
|
||||
"favorite_pages": [],
|
||||
"shared_pages": [],
|
||||
"shared_made_pages": [],
|
||||
"shared_received_pages": [],
|
||||
"published_pages": [],
|
||||
"shared_pages": shared_pages,
|
||||
"shared_made_pages": shared_made_pages,
|
||||
"shared_received_pages": shared_received_pages,
|
||||
"published_pages": published_pages,
|
||||
"user": user,
|
||||
"avatar_url": avatar_url,
|
||||
"avatar_color": avatar_color,
|
||||
|
||||
Reference in New Issue
Block a user