feat: sidebar Repository identique au Workspace-local, pages forge unifiees, GC miroirs vides
FlowDeck CI / lint (push) Successful in 1m37s
FlowDeck CI / test (push) Successful in 25m11s
FlowDeck CI / docker (push) Successful in 1m32s

This commit is contained in:
2026-10-09 22:33:34 -04:00
parent 9ea0cddf3c
commit d95178156f
13 changed files with 1110 additions and 175 deletions
+57 -25
View File
@@ -13,7 +13,13 @@ from app.auth.session import SessionManager
from app.db import get_conn
from app.services.gitea_client import get_user_gitea_client, gitea
from ._common import _get_active_workspace, _get_user_id, _sidebar_data
from ._common import (
_cleanup_empty_mirrors,
_ensure_forge_mirror,
_get_active_workspace,
_get_user_id,
_sidebar_data,
)
logger = logging.getLogger(__name__)
router = APIRouter(tags=["dashboard"])
@@ -125,12 +131,9 @@ def workspace_page(request: Request):
@router.get("/gitea-workspace", response_class=HTMLResponse)
def gitea_workspace_page(request: Request):
"""Gitea workspace — browse repo files."""
import json
"""Gitea workspace — browse repo files (same layout as /local-workspace)."""
from app.templating import ENV
env = ENV
sidebar = _sidebar_data(request, [])
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
if not user:
return RedirectResponse("/auth/login?provider=local", status_code=302)
@@ -138,27 +141,16 @@ def gitea_workspace_page(request: Request):
repo = request.query_params.get("repo", "")
ws_key = f"{owner}/{repo}" if owner and repo else ""
ws_name = ws_key or "Gitea Workspace"
# Auto-create local workspace mirror for storing local files
local_ws_id = None
# Ensure the local workspace mirror of the same name BEFORE building the
# sidebar, then drop other EMPTY mirrors so switching repositories never
# accumulates empty workspace-locals.
local_ws_id = _ensure_forge_mirror(user["id"], owner, repo, forge="gitea") if ws_key else None
if ws_key:
with get_conn() as conn:
existing = conn.execute(
"SELECT id, owner_id FROM workspaces WHERE owner_id=? AND name=? AND settings_json LIKE ?",
(user["id"], ws_key, "%gitea_repo%")
).fetchone()
if existing:
local_ws_id = existing["id"]
else:
c = conn.execute(
"INSERT INTO workspaces (name, owner_id, settings_json) VALUES (?, ?, ?)",
(ws_key, user["id"], json.dumps({"gitea_repo": ws_key, "gitea_owner": owner}))
)
local_ws_id = c.lastrowid
conn.execute(
"INSERT INTO workspace_members (workspace_id, user_id, role) VALUES (?, ?, ?)",
(local_ws_id, user["id"], "admin")
)
conn.commit()
_cleanup_empty_mirrors(user["id"], keep_name=ws_key, keep_id=local_ws_id or 0)
# Build the sidebar with the explicit project context so the local mirror
# (''Workspace'' section) is resolved even when the flowdeck_workspace
# cookie is absent (direct navigation / bookmark).
sidebar = _sidebar_data(request, [], gitea_owner=owner, gitea_repo=repo)
ctx = {
**sidebar,
"user": user,
@@ -167,6 +159,7 @@ def gitea_workspace_page(request: Request):
"gitea_workspace": True, # always true on this page
"gitea_owner": owner,
"gitea_repo": repo,
"forge": "gitea",
"workspace_name": ws_name,
"workspace_initial": repo[0].upper() if repo else "G",
"owner": owner,
@@ -179,6 +172,45 @@ def gitea_workspace_page(request: Request):
return resp
@router.get("/github-workspace", response_class=HTMLResponse)
def github_workspace_page(request: Request):
"""GitHub workspace — same layout as /local-workspace and /gitea-workspace."""
from app.templating import ENV
env = ENV
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
if not user:
return RedirectResponse("/auth/login?provider=local", status_code=302)
owner = request.query_params.get("owner", "")
repo = request.query_params.get("repo", "")
ws_key = f"{owner}/{repo}" if owner and repo else ""
ws_name = ws_key or "GitHub Workspace"
local_ws_id = _ensure_forge_mirror(user["id"], owner, repo, forge="github") if ws_key else None
if ws_key:
_cleanup_empty_mirrors(user["id"], keep_name=ws_key, keep_id=local_ws_id or 0)
# Reuse the same sidebar mechanism (Repository section + parallel local
# mirror). The cookie prefix carries the forge so refresh APIs resolve it.
sidebar = _sidebar_data(request, [], gitea_owner=owner, gitea_repo=repo)
ctx = {
**sidebar,
"user": user,
"active_ws_name": ws_name,
"workspace_key": ws_key,
"gitea_workspace": True, # sidebar Repository section visible
"gitea_owner": owner,
"gitea_repo": repo,
"forge": "github",
"workspace_name": ws_name,
"workspace_initial": repo[0].upper() if repo else "G",
"owner": owner,
"repo": repo,
"nav_workspace_id": local_ws_id or 0,
}
template = env.get_template("github_workspace.html")
resp = HTMLResponse(content=template.render(**ctx))
resp.set_cookie("flowdeck_workspace", f"github:{owner}:{repo}", path="/", samesite="lax")
return resp
@router.get("/api/workspace/projects")