feat: add web UI project registry and onboarding (#427)

Load projects from versioned webui/data/projects.registry.json with profile
mappings, workflow/schema paths, and read-only onboarding checklist UI.
Seeds Gitea-Tools; exposes /projects, /projects/{id}, and /api/projects.

Closes #427
This commit is contained in:
2026-07-07 14:44:27 -04:00
parent 30ded9b712
commit 16dcf65825
8 changed files with 529 additions and 7 deletions
+30 -4
View File
@@ -10,6 +10,8 @@ from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import Route
from webui.layout import render_page
from webui.project_registry import find_project, load_registry, registry_to_dict
from webui.project_views import render_project_detail, render_projects_list
_READ_ONLY_METHODS = frozenset({"GET", "HEAD", "OPTIONS"})
@@ -49,10 +51,32 @@ async def health(_request: Request) -> JSONResponse:
async def projects(_request: Request) -> HTMLResponse:
return _stub_page(
"Projects",
"Project registry and onboarding model will list configured repos and profiles.",
)
registry = load_registry()
return HTMLResponse(render_projects_list(registry))
async def project_detail(request: Request) -> HTMLResponse:
project_id = request.path_params["project_id"]
registry = load_registry()
project = find_project(registry, project_id)
if project is None:
return HTMLResponse(
render_page(
title="Project not found",
body_html=(
"<h2>Project not found</h2>"
f"<p>No registry entry for <code>{project_id}</code>.</p>"
'<p><a href="/projects">← All projects</a></p>'
),
),
status_code=404,
)
return HTMLResponse(render_project_detail(project))
async def api_projects(_request: Request) -> JSONResponse:
registry = load_registry()
return JSONResponse(registry_to_dict(registry))
async def prompts(_request: Request) -> HTMLResponse:
@@ -107,6 +131,8 @@ def create_app() -> Starlette:
Route("/", home, methods=["GET"]),
Route("/health", health, methods=["GET"]),
Route("/projects", projects, methods=["GET"]),
Route("/projects/{project_id}", project_detail, methods=["GET"]),
Route("/api/projects", api_projects, methods=["GET"]),
Route("/prompts", prompts, methods=["GET"]),
Route("/runtime", runtime, methods=["GET"]),
Route("/audit", audit, methods=["GET"]),