diff --git a/app/db.py b/app/db.py index 484350d..72accfc 100644 --- a/app/db.py +++ b/app/db.py @@ -137,10 +137,16 @@ def init_db(): title TEXT NOT NULL DEFAULT 'New page', content TEXT NOT NULL DEFAULT '', parent_section TEXT DEFAULT 'Private', + parent_id INTEGER REFERENCES pages(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); """) + # Migration: add parent_id if missing (v1.0.0+) + try: + conn.execute("ALTER TABLE pages ADD COLUMN parent_id INTEGER REFERENCES pages(id)") + except sqlite3.OperationalError: + pass conn.commit() diff --git a/app/routers/board.py b/app/routers/board.py index 65c0f82..5540c5e 100644 --- a/app/routers/board.py +++ b/app/routers/board.py @@ -139,7 +139,7 @@ def _sidebar_data(request: Request, owner: str = "", repo: str = "") -> dict: # Load pages for this project workspace with get_conn() as conn: pages = conn.execute( - "SELECT id, title, updated_at FROM pages WHERE workspace=? ORDER BY updated_at DESC LIMIT 10", + "SELECT id, title, parent_id, updated_at FROM pages WHERE workspace=? AND parent_id IS NULL ORDER BY updated_at DESC LIMIT 10", (ws_key,), ).fetchall() for p in pages: @@ -147,6 +147,16 @@ def _sidebar_data(request: Request, owner: str = "", repo: str = "") -> dict: "id": f"page/{p['id']}", "name": p["title"], "icon": "๐", "url": f"/pages/{p['id']}", "active": False, "indent": 0, }) + # Load sub-pages + subs = conn.execute( + "SELECT id, title FROM pages WHERE parent_id=? ORDER BY updated_at DESC", + (p["id"],), + ).fetchall() + for sp in subs: + recent.append({ + "id": f"page/{sp['id']}", "name": sp["title"], "icon": "ยท", + "url": f"/pages/{sp['id']}", "active": False, "indent": 1, + }) return {"workspace_name": ws_name, "workspace_initial": ws_name[0].upper() if ws_name else "B", "current_page": repo or "Dashboard", "last_edited": "now", "recent_pages": recent, "private_pages": [r for r in recent if r.get("active") or r["id"].startswith("page/")], @@ -439,18 +449,19 @@ async def extract_ai_keywords(owner: str, repo: str): @router.post("/api/pages") async def create_page(request: Request, title: str = Query(default="New page"), section: str = Query(default="Private"), - project: str = Query(default="")): - """Create a new Markdown page in the given project workspace.""" + project: str = Query(default=""), + parent_id: int = Query(default=0)): + """Create a new Markdown page, optionally as a sub-page.""" user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) ws_key = project if project else (user.get("login", "Bruno") if user else "Bruno") with get_conn() as conn: cur = conn.execute( - "INSERT INTO pages (workspace, title, parent_section) VALUES (?,?,?)", - (ws_key, title, section), + "INSERT INTO pages (workspace, title, parent_section, parent_id) VALUES (?,?,?,?)", + (ws_key, title, section, parent_id if parent_id > 0 else None), ) conn.commit() page_id = cur.lastrowid - return {"status": "ok", "id": page_id, "title": title, "workspace": ws_key} + return {"status": "ok", "id": page_id, "title": title, "workspace": ws_key, "parent_id": parent_id} @router.get("/api/pages/{page_id}") diff --git a/app/routers/dashboard.py b/app/routers/dashboard.py index 72fa367..10f45f5 100644 --- a/app/routers/dashboard.py +++ b/app/routers/dashboard.py @@ -71,7 +71,13 @@ async def view_page_root(request: Request, page_id: int): parts = ws.split("/") if "/" in ws else ["", ""] owner, repo = parts[0], parts[1] if len(parts) > 1 else "" sidebar = board_sidebar(request, owner, repo) - ctx = {**sidebar, "page": page} + # Load sub-pages + with get_conn() as conn: + subs = conn.execute( + "SELECT id, title FROM pages WHERE parent_id=? ORDER BY updated_at DESC", + (page_id,), + ).fetchall() + ctx = {**sidebar, "page": page, "sub_pages": [dict(s) for s in subs]} template = env.get_template("page_editor.html") return template.render(**ctx) diff --git a/app/templates/base.html b/app/templates/base.html index d61a145..17a8b70 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -436,7 +436,8 @@ }, newSubPage(parentId) { const project = this.workspaceKey || ''; - fetch(`/board/api/pages?title=New%20page§ion=Private&project=${encodeURIComponent(project)}`, { + const pid = parentId.replace('page/', ''); + fetch(`/board/api/pages?title=New%20sub-page§ion=Private&project=${encodeURIComponent(project)}&parent_id=${pid}`, { method: 'POST', headers: { 'X-CSRF-Token': this.getCsrfToken() } }) diff --git a/app/templates/page_editor.html b/app/templates/page_editor.html index ab1dac1..9548642 100644 --- a/app/templates/page_editor.html +++ b/app/templates/page_editor.html @@ -69,11 +69,36 @@ + + +