feat: add Notion-style breadcrumb navigation with dropdown menus
Backend: - Added _nav_breadcrumb() to build page hierarchy chain (root → current) - New /api/nav/menu endpoint returns workspace/folder children with has_children flag - view_page() and view_page_root() now pass breadcrumb_items, nav_workspace_id, nav_page_id to template Header template (_header.html): - Replaced static breadcrumb with Alpine.js fdBreadcrumb() component - Breadcrumb items now clickable with dropdown menus showing
This commit is contained in:
@@ -1847,3 +1847,70 @@ def test_gitea_private_pages_create_no_auth(client):
|
||||
"""POST private-pages — 401 without session."""
|
||||
resp = client.post("/api/gitea/projects/owner/repo/private-pages", json={"title": "Test"})
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
# ── v2.6.0: Notion-style breadcrumb navigation ──
|
||||
|
||||
def test_nav_menu_endpoint_responds(client):
|
||||
"""GET /api/nav/menu — always returns an items list (200)."""
|
||||
resp = client.get("/api/nav/menu")
|
||||
assert resp.status_code == 200
|
||||
assert "items" in resp.json()
|
||||
|
||||
|
||||
def test_nav_menu_workspace_pages(client):
|
||||
"""/api/nav/menu returns root pages and nested children for a workspace."""
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
u = conn.execute("INSERT OR IGNORE INTO users (login) VALUES ('navuser')")
|
||||
uid = conn.execute("SELECT id FROM users WHERE login='navuser'").fetchone()["id"]
|
||||
cur = conn.execute("INSERT INTO workspaces (name, owner_id) VALUES ('NavWS', ?)", (uid,))
|
||||
ws_id = cur.lastrowid
|
||||
p = conn.execute(
|
||||
"INSERT INTO pages (workspace, workspace_id, title, content, content_format, "
|
||||
"parent_section, parent_id) VALUES ('NavWS', ?, 'Parent Page', '', 'blocks', 'Private', NULL)",
|
||||
(ws_id,),
|
||||
)
|
||||
parent_id = p.lastrowid
|
||||
conn.execute(
|
||||
"INSERT INTO pages (workspace, workspace_id, title, content, content_format, "
|
||||
"parent_section, parent_id) VALUES ('NavWS', ?, 'Child Page', '', 'blocks', 'Private', ?)",
|
||||
(ws_id, parent_id),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
# Root level should list the parent and flag it as having children
|
||||
resp = client.get(f"/api/nav/menu?workspace_id={ws_id}")
|
||||
assert resp.status_code == 200
|
||||
items = resp.json()["items"]
|
||||
names = {i["name"]: i for i in items}
|
||||
assert "Parent Page" in names
|
||||
assert names["Parent Page"]["has_children"] is True
|
||||
|
||||
# Children of the parent should include the child page
|
||||
resp = client.get(f"/api/nav/menu?workspace_id={ws_id}&parent_id={parent_id}")
|
||||
child_names = {i["name"] for i in resp.json()["items"]}
|
||||
assert "Child Page" in child_names
|
||||
|
||||
|
||||
def test_page_renders_breadcrumb_data(client):
|
||||
"""Rendered page includes the breadcrumb JSON payload with a Home crumb."""
|
||||
from app.db import get_conn
|
||||
with get_conn() as conn:
|
||||
conn.execute("INSERT OR IGNORE INTO users (login) VALUES ('crumbuser')")
|
||||
uid = conn.execute("SELECT id FROM users WHERE login='crumbuser'").fetchone()["id"]
|
||||
cur = conn.execute("INSERT INTO workspaces (name, owner_id) VALUES ('CrumbWS', ?)", (uid,))
|
||||
ws_id = cur.lastrowid
|
||||
p = conn.execute(
|
||||
"INSERT INTO pages (workspace, workspace_id, title, content, content_format, "
|
||||
"parent_section, parent_id) VALUES ('CrumbWS', ?, 'Crumb Page', '', 'blocks', 'Private', NULL)",
|
||||
(ws_id,),
|
||||
)
|
||||
page_id = p.lastrowid
|
||||
conn.commit()
|
||||
|
||||
resp = client.get(f"/pages/{page_id}")
|
||||
assert resp.status_code == 200
|
||||
assert 'id="fd-breadcrumb-data"' in resp.text
|
||||
assert '"Home"' in resp.text
|
||||
assert "fdBreadcrumb" in resp.text
|
||||
|
||||
Reference in New Issue
Block a user