fix: resolve 3 critical UI bugs
1. Refresh button no longer doubles header - Added ?fragment=1 param to filter/refresh HTMX requests - Board route returns board_fragment.html (columns only) for fragment requests - Refresh button uses window.location.reload() for full page reload 2. No more raw JSON in header - base.html: user info rendered server-side via template variable - board.py: decodes session cookie, passes user to template - Dashboard/board templates show Login/Deconnexion based on auth state 3. New issue form works - Replaced HTMX post with JS fetch (handleNewIssue) - Adds CSRF token to form submission - Reloads page on successful creation - Cleaner error handling
This commit is contained in:
+23
-36
@@ -50,45 +50,32 @@ async def board(
|
||||
milestone: str = "",
|
||||
label: str = "",
|
||||
assignee: str = "",
|
||||
fragment: bool = False,
|
||||
):
|
||||
"""Kanban board for a Gitea project."""
|
||||
try:
|
||||
# Get issues
|
||||
issues = await gitea.get_issues(owner, repo, state="all")
|
||||
|
||||
# Get labels
|
||||
labels = await gitea.get_labels(owner, repo)
|
||||
|
||||
# Get milestones
|
||||
labels_list = await gitea.get_labels(owner, repo)
|
||||
milestones = await gitea.get_milestones(owner, repo)
|
||||
|
||||
# Filter by milestone
|
||||
if milestone:
|
||||
issues = [i for i in issues if i.get("milestone", {}).get("title") == milestone]
|
||||
|
||||
# Filter by label
|
||||
if label:
|
||||
issues = [i for i in issues if any(lbl["name"] == label for lbl in i.get("labels", []))]
|
||||
|
||||
# Filter by assignee
|
||||
if assignee:
|
||||
issues = [i for i in issues if i.get("assignee", {}).get("login") == assignee]
|
||||
|
||||
# Separate PRs from issues (ponytail: PRs are also in /issues endpoint)
|
||||
prs = [i for i in issues if "pull_request" in i]
|
||||
issues_only = [i for i in issues if "pull_request" not in i]
|
||||
|
||||
# Get board config
|
||||
board_info = _ensure_board(owner, repo)
|
||||
columns = board_info["columns"]
|
||||
cards = _get_cards(board_info["id"])
|
||||
|
||||
# Map issues to columns
|
||||
column_map: dict[str, list[dict]] = {col: [] for col in columns}
|
||||
card_by_issue = {c["gitea_issue_id"]: c for c in cards if c["gitea_issue_id"]}
|
||||
|
||||
for issue in issues_only:
|
||||
# Determine column from issue state/labels first, then from DB position
|
||||
col = _issue_column(issue, columns, board_info["id"])
|
||||
issue["_col"] = col
|
||||
issue["_card"] = card_by_issue.get(issue["number"])
|
||||
@@ -97,37 +84,37 @@ async def board(
|
||||
except Exception as e:
|
||||
from httpx import HTTPStatusError
|
||||
if isinstance(e, HTTPStatusError) and e.response is not None and e.response.status_code == 404:
|
||||
html = '<div style="padding:48px;text-align:center">'
|
||||
html += '<h2 style="color:var(--text-dim)">Projet introuvable</h2>'
|
||||
html += f'<p style="color:var(--text-dim)">{owner}/{repo} n\'existe pas sur Gitea.</p>'
|
||||
html += '<a href="/" class="btn btn-primary" style="margin-top:16px">Retour aux projets</a>'
|
||||
html += '</div>'
|
||||
return HTMLResponse(html, status_code=404)
|
||||
return HTMLResponse(
|
||||
'<div style="padding:48px;text-align:center">'
|
||||
f'<h2 style="color:#8b949e">Projet introuvable</h2>'
|
||||
f'<p style="color:#8b949e">{owner}/{repo} n\'existe pas sur Gitea.</p>'
|
||||
'<a href="/" class="btn btn-primary" style="margin-top:16px">Retour aux projets</a></div>',
|
||||
status_code=404)
|
||||
logger.error("Board error: %s", e)
|
||||
return HTMLResponse(f"<p class='error'>Erreur: {e}</p>", status_code=500)
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from datetime import datetime
|
||||
from app.config import settings
|
||||
from app.auth.session import SessionManager
|
||||
|
||||
env = Environment(loader=FileSystemLoader("app/templates"))
|
||||
template = env.get_template("board.html")
|
||||
return template.render(
|
||||
request=request,
|
||||
owner=owner,
|
||||
repo=repo,
|
||||
columns=columns,
|
||||
column_map=column_map,
|
||||
labels=labels,
|
||||
milestones=milestones,
|
||||
current_milestone=milestone,
|
||||
current_label=label,
|
||||
current_assignee=assignee,
|
||||
prs=prs,
|
||||
settings=settings,
|
||||
now=datetime.now().isoformat()[:10],
|
||||
now_str = datetime.now().isoformat()[:10]
|
||||
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
|
||||
|
||||
ctx = dict(
|
||||
request=request, owner=owner, repo=repo, columns=columns,
|
||||
column_map=column_map, labels=labels_list, milestones=milestones,
|
||||
current_milestone=milestone, current_label=label, current_assignee=assignee,
|
||||
prs=prs, settings=settings, now=now_str, user=user,
|
||||
)
|
||||
|
||||
if fragment:
|
||||
template = env.get_template("board_fragment.html")
|
||||
else:
|
||||
template = env.get_template("board.html")
|
||||
return template.render(**ctx)
|
||||
|
||||
|
||||
def _issue_column(issue: dict, columns: list[str], board_id: int) -> str:
|
||||
"""Determine which column an issue belongs to."""
|
||||
|
||||
Reference in New Issue
Block a user