feat: add publish to L2 button in run detail web UI

- Add POST /ui/publish-run/{run_id} endpoint for UI publishing
- Add publish form with HTMX to run detail page
- Shows publish button for completed runs with outputs
- Uses existing L2 /registry/record-run endpoint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-07 19:12:46 +00:00
parent 85f349a7ab
commit 917146a7f3

View File

@@ -1291,6 +1291,42 @@ async def ui_logout():
return response
@app.post("/ui/publish-run/{run_id}", response_class=HTMLResponse)
async def ui_publish_run(run_id: str, request: Request, output_name: str = Form(...)):
"""Publish a run to L2 from the web UI."""
token = request.cookies.get("auth_token")
if not token:
return HTMLResponse('<div class="error">Not logged in</div>')
# Call L2 to publish the run
try:
resp = http_requests.post(
f"{L2_SERVER}/registry/record-run",
json={"run_id": run_id, "output_name": output_name},
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
if resp.status_code == 400:
error = resp.json().get("detail", "Bad request")
return HTMLResponse(f'<div class="error">Error: {error}</div>')
resp.raise_for_status()
result = resp.json()
return HTMLResponse(f'''
<div class="success" style="background:#1a4d1a;color:#4ade80;padding:10px;border-radius:4px;margin-bottom:10px;">
Published to L2 as <strong>{result["asset"]["name"]}</strong>
</div>
''')
except http_requests.exceptions.HTTPError as e:
error_detail = ""
try:
error_detail = e.response.json().get("detail", str(e))
except Exception:
error_detail = str(e)
return HTMLResponse(f'<div class="error" style="background:#4d1a1a;color:#f87171;padding:10px;border-radius:4px;">Error: {error_detail}</div>')
except Exception as e:
return HTMLResponse(f'<div class="error" style="background:#4d1a1a;color:#f87171;padding:10px;border-radius:4px;">Error: {e}</div>')
@app.get("/ui/runs", response_class=HTMLResponse)
async def ui_runs(request: Request):
"""HTMX partial: list of runs."""
@@ -1557,6 +1593,7 @@ async def ui_detail_page(run_id: str, request: Request):
<html>
<head>
<title>{run.recipe} - {run.run_id[:8]} | Art DAG L1</title>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<style>{UI_CSS}</style>
</head>
<body>
@@ -1706,6 +1743,27 @@ async def ui_detail_page(run_id: str, request: Request):
html += f'''
<h2>Raw JSON</h2>
<pre style="background:#0a0a0a;padding:16px;border-radius:8px;overflow-x:auto;font-size:13px;"><code>{provenance_json}</code></pre>
'''
# Add publish section for completed runs
if run.status == "completed" and run.output_hash:
html += f'''
<h2>Publish to L2</h2>
<p style="color:#888;font-size:14px;">Register this transformation output on the L2 ActivityPub server.</p>
<div id="publish-result"></div>
<form hx-post="/ui/publish-run/{run.run_id}" hx-target="#publish-result" hx-swap="innerHTML"
style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
<input type="text" name="output_name" value="{run.output_name}"
placeholder="Asset name" required
style="padding:10px;background:#222;border:1px solid #444;border-radius:4px;color:#eee;min-width:200px;">
<button type="submit"
style="padding:10px 20px;background:#2563eb;color:#fff;border:none;border-radius:4px;cursor:pointer;">
Publish to L2
</button>
</form>
'''
html += '''
</div>
</div>
</body>