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):