mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-07 17:33:35 -10:00
* fix: surface platform-board integration errors instead of empty state (fixes #74) Distinguish connection, auth, and HTTP failures from zero issues. Add __main__ uvicorn bootstrap with HOST/PORT env overrides. Co-authored-by: Cursor <[email protected]> * fix: improve platform-board error handling - Add explicit 200 status code check to prevent 3xx/204 from proceeding to JSON parsing - Add safe JSON parsing with try/catch to handle invalid JSON responses - Add defensive type checking for non-dict/non-list JSON responses Addresses reviewer feedback from Gemini Code Assist review. Co-authored-by: Mervin Praison <[email protected]> --------- Co-authored-by: MervinPraison <[email protected]> Co-authored-by: Cursor <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Mervin Praison <[email protected]>
90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
"""Board from praisonai-platform issues (optional separate service)."""
|
|
|
|
import os
|
|
|
|
import httpx
|
|
import praisonaiui as aiui
|
|
from praisonaiui.server import create_app
|
|
|
|
PLATFORM = os.getenv("PRAISONAI_PLATFORM_URL", "http://127.0.0.1:8000")
|
|
WORKSPACE_ID = os.getenv("PRAISONAI_PLATFORM_WORKSPACE_ID", "default")
|
|
|
|
aiui.set_style("dashboard")
|
|
aiui.set_pages(["issues-board"])
|
|
aiui.set_dashboard(sidebar=True)
|
|
|
|
|
|
async def _fetch_issues() -> tuple[list, str | None]:
|
|
"""Return (issues, error_message). error_message is None on success."""
|
|
url = f"{PLATFORM.rstrip('/')}/api/v1/workspaces/{WORKSPACE_ID}/issues"
|
|
try:
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
response = await client.get(url)
|
|
except httpx.ConnectError:
|
|
return [], f"Cannot reach platform at {PLATFORM}"
|
|
except httpx.TimeoutException:
|
|
return [], f"Platform request timed out ({PLATFORM})"
|
|
except Exception as exc:
|
|
return [], f"Platform request failed: {exc}"
|
|
|
|
if response.status_code in (401, 403):
|
|
return [], f"Platform auth failed (HTTP {response.status_code})"
|
|
if response.status_code != 200:
|
|
return [], f"Platform error (HTTP {response.status_code})"
|
|
|
|
try:
|
|
data = response.json()
|
|
except ValueError:
|
|
return [], "Platform returned invalid JSON"
|
|
|
|
if isinstance(data, list):
|
|
issues = data
|
|
elif isinstance(data, dict):
|
|
issues = data.get("issues") or data.get("items") or []
|
|
else:
|
|
issues = []
|
|
return issues, None
|
|
|
|
|
|
@aiui.page("issues-board", title="Issues", icon="📌", group="Work")
|
|
async def issues_board():
|
|
issues, error = await _fetch_issues()
|
|
|
|
if error:
|
|
return aiui.layout([
|
|
aiui.text(f"Platform: {PLATFORM} · workspace: {WORKSPACE_ID}"),
|
|
aiui.card("Platform unavailable", footer=error),
|
|
])
|
|
|
|
by: dict[str, list] = {}
|
|
for issue in issues:
|
|
status = (issue.get("status") or "backlog").lower().replace(" ", "_")
|
|
by.setdefault(status, []).append(issue)
|
|
|
|
columns = []
|
|
for status_id in ("backlog", "in_progress", "done"):
|
|
cards = [aiui.card(i.get("title", "Issue"), footer=status_id) for i in by.get(status_id, [])]
|
|
if not cards:
|
|
cards = [aiui.card("(no issues)")]
|
|
columns.append({
|
|
"id": status_id,
|
|
"title": status_id.replace("_", " ").title(),
|
|
"cards": cards,
|
|
})
|
|
|
|
summary = f"{len(issues)} issue(s)" if issues else "No issues in workspace"
|
|
return aiui.layout([
|
|
aiui.text(f"Platform: {PLATFORM} · workspace: {WORKSPACE_ID} · {summary}"),
|
|
aiui.board(columns=columns),
|
|
])
|
|
|
|
|
|
app = create_app()
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
host = os.getenv("HOST", "127.0.0.1")
|
|
port = int(os.getenv("PORT", "8082"))
|
|
uvicorn.run(app, host=host, port=port)
|