Add delete button for runs in UI
- Add delete_html section to run detail page with delete button
- Add /ui/runs/{run_id}/discard HTMX endpoint
- Failed runs can always be deleted without restrictions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
66
server.py
66
server.py
@@ -437,6 +437,55 @@ async def discard_run(run_id: str, username: str = Depends(get_required_user)):
|
||||
return {"discarded": True, "run_id": run_id}
|
||||
|
||||
|
||||
@app.delete("/ui/runs/{run_id}/discard", response_class=HTMLResponse)
|
||||
async def ui_discard_run(run_id: str, request: Request):
|
||||
"""HTMX handler: discard a run."""
|
||||
current_user = get_user_from_cookie(request)
|
||||
if not current_user:
|
||||
return '<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Login required</div>'
|
||||
|
||||
run = load_run(run_id)
|
||||
if not run:
|
||||
return '<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Run not found</div>'
|
||||
|
||||
# Check ownership
|
||||
actor_id = f"@{current_user}@{L2_DOMAIN}"
|
||||
if run.username not in (current_user, actor_id):
|
||||
return '<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Access denied</div>'
|
||||
|
||||
# Failed runs can always be deleted
|
||||
if run.status != "failed":
|
||||
# Check if activity exists for this run
|
||||
activity = cache_manager.get_activity(run_id)
|
||||
|
||||
if activity:
|
||||
can_discard, reason = cache_manager.can_discard_activity(run_id)
|
||||
if not can_discard:
|
||||
return f'<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Cannot discard: {reason}</div>'
|
||||
|
||||
success, msg = cache_manager.discard_activity(run_id)
|
||||
if not success:
|
||||
return f'<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Failed to discard: {msg}</div>'
|
||||
else:
|
||||
# Legacy run - check L2 shared status
|
||||
items_to_check = list(run.inputs or [])
|
||||
if run.output_hash:
|
||||
items_to_check.append(run.output_hash)
|
||||
|
||||
for content_hash in items_to_check:
|
||||
if cache_manager.l2_checker.is_shared(content_hash):
|
||||
return f'<div class="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-4">Cannot discard: item {content_hash[:16]}... is published to L2</div>'
|
||||
|
||||
# Remove from Redis
|
||||
redis_client.delete(f"{RUNS_KEY_PREFIX}{run_id}")
|
||||
|
||||
return '''
|
||||
<div class="bg-green-900/50 border border-green-700 text-green-300 px-4 py-3 rounded-lg mb-4">
|
||||
Run deleted. <a href="/runs" class="underline">Back to runs</a>
|
||||
</div>
|
||||
'''
|
||||
|
||||
|
||||
@app.get("/run/{run_id}")
|
||||
async def run_detail(run_id: str, request: Request):
|
||||
"""Run detail. HTML for browsers, JSON for APIs."""
|
||||
@@ -590,6 +639,22 @@ async def run_detail(run_id: str, request: Request):
|
||||
</div>
|
||||
'''
|
||||
|
||||
# Delete section
|
||||
delete_html = f'''
|
||||
<div class="border-t border-dark-500 pt-6 mt-6">
|
||||
<h2 class="text-lg font-semibold text-white mb-3">Delete Run</h2>
|
||||
<p class="text-sm text-gray-400 mb-4">
|
||||
{"This run failed and can be deleted." if run.status == "failed" else "Delete this run and its associated cache entries."}
|
||||
</p>
|
||||
<div id="delete-result"></div>
|
||||
<button hx-delete="/ui/runs/{run.run_id}/discard" hx-target="#delete-result" hx-swap="innerHTML"
|
||||
hx-confirm="Are you sure you want to delete this run? This cannot be undone."
|
||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white font-medium rounded-lg transition-colors">
|
||||
Delete Run
|
||||
</button>
|
||||
</div>
|
||||
'''
|
||||
|
||||
output_link = ""
|
||||
if run.output_hash:
|
||||
output_link = f'''<div class="bg-dark-600 rounded-lg p-4">
|
||||
@@ -661,6 +726,7 @@ async def run_detail(run_id: str, request: Request):
|
||||
</div>
|
||||
|
||||
{publish_html}
|
||||
{delete_html}
|
||||
</div>
|
||||
'''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user