fix: Library preserves sidebar tree and categorizes by parent_section
FlowDeck CI / test (push) Failing after 8s
FlowDeck CI / docker (push) Has been skipped

- Sidebar data (board._sidebar_data()) no longer overwritten by library content
- New variables: lib_recent, lib_favorites, lib_shared, lib_private
- Pages categorized by parent_section column: Private/Favorites/Shared
- Recents tab shows all non-trashed pages ordered by updated_at
- library.html updated to use lib_* variables instead of sidebar data
- Favorites/Shared tabs hidden when empty (lib_has_favorites/lib_has_shared)
This commit is contained in:
2026-07-10 09:31:18 -04:00
parent a251ccfe2d
commit fbf0335c3a
2 changed files with 51 additions and 34 deletions
+38 -28
View File
@@ -71,42 +71,52 @@ async def trash_page(request: Request, owner: str = Query(default=""), repo: str
@router.get("/library", response_class=HTMLResponse) @router.get("/library", response_class=HTMLResponse)
async def library_page(request: Request, owner: str = Query(default=""), repo: str = Query(default="")): 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.""" """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 jinja2 import Environment, FileSystemLoader
from app.routers.board import _sidebar_data as board_sidebar from app.routers.board import _sidebar_data as board_sidebar
env = Environment(loader=FileSystemLoader("app/templates")) env = Environment(loader=FileSystemLoader("app/templates"))
sidebar = board_sidebar(request, owner, repo) sidebar = board_sidebar(request, owner, repo) # Sidebar intacte, inchangée
# Load all pages for the workspace from DB
ws_key = f"{owner}/{repo}" if owner and repo else "" ws_key = f"{owner}/{repo}" if owner and repo else ""
with get_conn() as conn: 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: if ws_key:
rows = conn.execute( base_query += " AND workspace=?"
"SELECT id, title, workspace, updated_at FROM pages " params.append(ws_key)
"WHERE workspace=? ORDER BY updated_at DESC", base_query += " ORDER BY updated_at DESC"
(ws_key,), rows = conn.execute(base_query, params).fetchall()
).fetchall()
else: def to_page(r):
rows = conn.execute( r = dict(r)
"SELECT id, title, workspace, updated_at FROM pages " return {
"ORDER BY updated_at DESC", "id": f"page/{r['id']}",
).fetchall() "name": r["title"] or "Untitled",
all_pages = []
for r in rows:
page = dict(r)
all_pages.append({
"id": f"page/{page['id']}",
"name": page["title"] or "Untitled",
"icon": "📄", "icon": "📄",
"url": f"/pages/{page['id']}", "url": f"/pages/{r['id']}",
"created_by": "You", "created_by": "You",
"source": page.get("workspace") or "🔒 Private", "source": r.get("workspace") or "🔒 Private",
"last_edited": page.get("updated_at", "now"), "last_edited": r.get("updated_at", "now"),
"last_visited": page.get("updated_at", "now"), "last_visited": r.get("updated_at", "now"),
}) }
sidebar["recent_pages"] = all_pages
sidebar["favorite_pages"] = [] all_pages = [to_page(r) for r in rows]
sidebar["private_pages"] = [p for p in all_pages if p.get("source") == "🔒 Private"]
sidebar["shared_pages"] = [] # Catégoriser par parent_section — sidebar data intacte
sidebar["lib_recent"] = all_pages
sidebar["lib_favorites"] = [p for p, r in zip(all_pages, rows) if (r["parent_section"] or "") == "Favorites"]
sidebar["lib_shared"] = [p for p, r in zip(all_pages, rows) if (r["parent_section"] or "") == "Shared"]
sidebar["lib_private"] = [p for p, r in zip(all_pages, rows) if (r["parent_section"] or "Private") == "Private"]
sidebar["lib_has_favorites"] = len(sidebar["lib_favorites"]) > 0
sidebar["lib_has_shared"] = len(sidebar["lib_shared"]) > 0
template = env.get_template("library.html") template = env.get_template("library.html")
return template.render(**sidebar) return template.render(**sidebar)
+13 -6
View File
@@ -15,12 +15,16 @@
<button class="view-tab" :class="{ active: tab === 'recents' }" @click="tab = 'recents'"> <button class="view-tab" :class="{ active: tab === 'recents' }" @click="tab = 'recents'">
<span class="tab-icon">🕒</span> Recents <span class="tab-icon">🕒</span> Recents
</button> </button>
{% if lib_has_favorites %}
<button class="view-tab" :class="{ active: tab === 'favorites' }" @click="tab = 'favorites'"> <button class="view-tab" :class="{ active: tab === 'favorites' }" @click="tab = 'favorites'">
<span class="tab-icon">⭐</span> Favorites <span class="tab-icon">⭐</span> Favorites
</button> </button>
{% endif %}
{% if lib_has_shared %}
<button class="view-tab" :class="{ active: tab === 'shared' }" @click="tab = 'shared'"> <button class="view-tab" :class="{ active: tab === 'shared' }" @click="tab = 'shared'">
<span class="tab-icon">👥</span> Shared <span class="tab-icon">👥</span> Shared
</button> </button>
{% endif %}
<button class="view-tab" :class="{ active: tab === 'private' }" @click="tab = 'private'"> <button class="view-tab" :class="{ active: tab === 'private' }" @click="tab = 'private'">
<span class="tab-icon">🔒</span> Private <span class="tab-icon">🔒</span> Private
</button> </button>
@@ -61,8 +65,8 @@
<!-- Recents --> <!-- Recents -->
<div x-show="tab === 'recents'"> <div x-show="tab === 'recents'">
{% for page in recent_pages %}{{ page_row(page) }}{% endfor %} {% for page in lib_recent %}{{ page_row(page) }}{% endfor %}
{% if not recent_pages %} {% if not lib_recent %}
<div class="lib-empty"> <div class="lib-empty">
<div style="font-size:48px;margin-bottom:16px;">🕒</div> <div style="font-size:48px;margin-bottom:16px;">🕒</div>
<h3>No recent pages</h3> <h3>No recent pages</h3>
@@ -72,8 +76,8 @@
<!-- Favorites --> <!-- Favorites -->
<div x-show="tab === 'favorites'"> <div x-show="tab === 'favorites'">
{% for page in favorite_pages %}{{ page_row(page) }}{% endfor %} {% for page in lib_favorites %}{{ page_row(page) }}{% endfor %}
{% if not favorite_pages %} {% if not lib_favorites %}
<div class="lib-empty"> <div class="lib-empty">
<div style="font-size:48px;margin-bottom:16px;">⭐</div> <div style="font-size:48px;margin-bottom:16px;">⭐</div>
<h3>No favorites</h3> <h3>No favorites</h3>
@@ -84,17 +88,20 @@
<!-- Shared --> <!-- Shared -->
<div x-show="tab === 'shared'"> <div x-show="tab === 'shared'">
{% for page in lib_shared %}{{ page_row(page) }}{% endfor %}
{% if not lib_shared %}
<div class="lib-empty"> <div class="lib-empty">
<div style="font-size:48px;margin-bottom:16px;">👥</div> <div style="font-size:48px;margin-bottom:16px;">👥</div>
<h3>No shared pages</h3> <h3>No shared pages</h3>
<p>Shared pages from your team will appear here.</p> <p>Shared pages from your team will appear here.</p>
</div> </div>
{% endif %}
</div> </div>
<!-- Private --> <!-- Private -->
<div x-show="tab === 'private'"> <div x-show="tab === 'private'">
{% for page in private_pages %}{{ page_row(page) }}{% endfor %} {% for page in lib_private %}{{ page_row(page) }}{% endfor %}
{% if not private_pages %} {% if not lib_private %}
<div class="lib-empty"> <div class="lib-empty">
<div style="font-size:48px;margin-bottom:16px;">🔒</div> <div style="font-size:48px;margin-bottom:16px;">🔒</div>
<h3>No private pages</h3> <h3>No private pages</h3>