From 98a330c416278dcb68ada540b5c6209c0735c027 Mon Sep 17 00:00:00 2001 From: Mike Wichers Date: Sun, 22 Feb 2026 10:05:30 -0500 Subject: [PATCH] Add run tagging (DB column + migration + route + UI) - Added tags VARCHAR(300) column to Run model - Added startup ALTER TABLE migration in app.py - New POST /run//set_tags route saves comma-separated tags - Tag badges + collapsible edit form in run_details.html header area Co-Authored-By: Claude Sonnet 4.6 --- templates/run_details.html | 22 ++++++++++++++++++++++ web/app.py | 8 ++++++++ web/db.py | 2 ++ web/routes/run.py | 16 ++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/templates/run_details.html b/templates/run_details.html index ed0bd72..8102ea2 100644 --- a/templates/run_details.html +++ b/templates/run_details.html @@ -108,6 +108,28 @@ + +
+ {% if run.tags %} + {% for tag in run.tags.split(',') %} + {{ tag }} + {% endfor %} + {% else %} + No tags + {% endif %} + +
+
+ + +
+
+
+
diff --git a/web/app.py b/web/app.py index 1039b20..1923a1b 100644 --- a/web/app.py +++ b/web/app.py @@ -116,6 +116,14 @@ with app.app_context(): _log("System: Added 'last_heartbeat' column to Run table.") except: pass + # Migration: Add 'tags' column if missing + try: + with db.engine.connect() as conn: + conn.execute(text("ALTER TABLE run ADD COLUMN tags VARCHAR(300)")) + conn.commit() + _log("System: Added 'tags' column to Run table.") + except: pass + # Reset all non-terminal runs on startup (running, queued, interrupted) # The Huey consumer restarts with the app, so any in-flight tasks are gone. try: diff --git a/web/db.py b/web/db.py index cc761b7..49da570 100644 --- a/web/db.py +++ b/web/db.py @@ -35,6 +35,8 @@ class Run(db.Model): progress = db.Column(db.Integer, default=0) last_heartbeat = db.Column(db.DateTime, nullable=True) + tags = db.Column(db.String(300), nullable=True) + logs = db.relationship('LogEntry', backref='run', lazy=True, cascade="all, delete-orphan") def duration(self): diff --git a/web/routes/run.py b/web/routes/run.py index 51d5357..fdd7118 100644 --- a/web/routes/run.py +++ b/web/routes/run.py @@ -394,6 +394,22 @@ def revise_book(run_id, book_folder): return redirect(url_for('run.view_run', id=new_run.id)) +@run_bp.route('/run//set_tags', methods=['POST']) +@login_required +def set_tags(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 + + raw = request.form.get('tags', '') + tags = [t.strip() for t in raw.split(',') if t.strip()] + run.tags = ','.join(dict.fromkeys(tags)) + db.session.commit() + + flash("Tags updated.") + return redirect(url_for('run.view_run', id=id)) + + @run_bp.route('/run//delete', methods=['POST']) @login_required def delete_run(id):