From af2050160e29a3c73ef814e44932c550a26e70ac Mon Sep 17 00:00:00 2001 From: Mike Wichers Date: Sun, 22 Feb 2026 10:04:44 -0500 Subject: [PATCH] Add run deletion with filesystem cleanup - New POST /run//delete route removes run from DB and deletes run directory - Only allows deletion of non-active runs (blocks running/queued) - Delete Run button shown in run_details.html header for non-active runs Co-Authored-By: Claude Sonnet 4.6 --- templates/run_details.html | 10 +++++++++- web/routes/run.py | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/templates/run_details.html b/templates/run_details.html index 9f2c435..ed0bd72 100644 --- a/templates/run_details.html +++ b/templates/run_details.html @@ -16,7 +16,15 @@ - Back to Project + {% if run.status not in ['running', 'queued'] %} +
+ +
+ {% endif %} + Back to Project diff --git a/web/routes/run.py b/web/routes/run.py index 117b2e9..51d5357 100644 --- a/web/routes/run.py +++ b/web/routes/run.py @@ -1,5 +1,6 @@ import os import json +import shutil import markdown from datetime import datetime from flask import Blueprint, render_template, request, redirect, url_for, flash, session, send_from_directory @@ -393,6 +394,30 @@ def revise_book(run_id, book_folder): return redirect(url_for('run.view_run', id=new_run.id)) +@run_bp.route('/run//delete', methods=['POST']) +@login_required +def delete_run(id): + run = db.session.get(Run, id) + if not run: return "Run not found", 404 + if run.project.user_id != current_user.id: return "Unauthorized", 403 + + if run.status in ['running', 'queued']: + flash("Cannot delete an active run. Stop it first.") + return redirect(url_for('run.view_run', id=id)) + + project_id = run.project_id + + run_dir = os.path.join(run.project.folder_path, "runs", f"run_{run.id}") + if os.path.exists(run_dir): + shutil.rmtree(run_dir) + + db.session.delete(run) + db.session.commit() + + flash(f"Run #{id} deleted successfully.") + return redirect(url_for('project.view_project', id=project_id)) + + @run_bp.route('/run//download_bible') @login_required def download_bible(id):