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:
58
server.py
58
server.py
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user