Remove /ui redirect routes, add 404 page, update README

- Remove obsolete /ui, /ui/login, /ui/register, /ui/logout redirects
- Fix /ui/login links to use /login directly
- Add styled 404 page for HTML requests
- Add Web UI section to README documenting routes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-09 10:42:14 +00:00
parent 1194251788
commit 5344fe263f
2 changed files with 66 additions and 28 deletions

View File

@@ -129,6 +129,57 @@ app = FastAPI(
)
@app.exception_handler(404)
async def not_found_handler(request: Request, exc):
"""Custom 404 page."""
from fastapi.responses import JSONResponse
accept = request.headers.get("accept", "")
if "text/html" in accept:
content = '''
<div class="text-center py-16">
<h2 class="text-6xl font-bold text-gray-600 mb-4">404</h2>
<p class="text-xl text-gray-400 mb-8">Page not found</p>
<a href="/" class="text-blue-400 hover:text-blue-300">Go to home page</a>
</div>
'''
# Import render_page at runtime to avoid circular dependency
html = f"""<!DOCTYPE html>
<html class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Not Found | Art DAG L1 Server</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {{
darkMode: 'class',
theme: {{
extend: {{
colors: {{
dark: {{ 900: '#0a0a0a', 800: '#111', 700: '#1a1a1a', 600: '#222', 500: '#333' }}
}}
}}
}}
}}
</script>
</head>
<body class="bg-dark-900 text-gray-100 min-h-screen">
<div class="max-w-6xl mx-auto px-4 py-6 sm:px-6 lg:px-8">
<header class="flex flex-wrap items-center justify-between gap-4 mb-6">
<h1 class="text-2xl font-bold">
<a href="/" class="text-white hover:text-gray-200">Art DAG L1 Server</a>
</h1>
</header>
<main class="bg-dark-700 rounded-lg p-6">
{content}
</main>
</div>
</body>
</html>"""
return HTMLResponse(html, status_code=404)
return JSONResponse({"detail": "Not found"}, status_code=404)
class RunRequest(BaseModel):
"""Request to start a run."""
recipe: str # Recipe name (e.g., "dog", "identity") or "dag" for custom DAG
@@ -1645,7 +1696,7 @@ async def ui_recipes_list(request: Request):
ctx = await get_user_context_from_cookie(request)
if not ctx:
return '<p class="text-gray-400 py-8 text-center"><a href="/ui/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see recipes.</p>'
return '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see recipes.</p>'
all_recipes = list_all_recipes()
@@ -3595,31 +3646,6 @@ async def logout():
return response
@app.get("/ui")
async def ui_index(tab: str = "runs"):
"""Redirect /ui to clean URLs."""
if tab == "cache":
return RedirectResponse(url="/media", status_code=302)
return RedirectResponse(url="/runs", status_code=302)
@app.get("/ui/login")
async def ui_login_page():
"""Redirect to L2 login."""
return RedirectResponse(url="/login", status_code=302)
@app.get("/ui/register")
async def ui_register_page():
"""Redirect to L2 register."""
return RedirectResponse(url="/register", status_code=302)
@app.get("/ui/logout")
async def ui_logout():
"""Redirect to logout."""
return RedirectResponse(url="/logout", status_code=302)
@app.post("/ui/publish-run/{run_id}", response_class=HTMLResponse)
async def ui_publish_run(run_id: str, request: Request, output_name: str = Form(...)):
@@ -3712,7 +3738,7 @@ async def ui_runs(request: Request):
# Require login to see runs
if not ctx:
return '<p class="text-gray-400 py-8 text-center"><a href="/ui/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see your runs.</p>'
return '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see your runs.</p>'
# Filter runs by user - match both plain username and ActivityPub format (@user@domain)
runs = [r for r in runs if r.username in (ctx.username, ctx.actor_id)]