This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new 211a31e  Add an admin route to show recent tasks
211a31e is described below

commit 211a31e3f93ff2d81622fe5064e8be765551bc92
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri Dec 5 10:14:54 2025 +0000

    Add an admin route to show recent tasks
---
 atr/admin/__init__.py               | 62 +++++++++++++++++++++++++++++++++++++
 atr/templates/includes/sidebar.html |  4 +++
 2 files changed, 66 insertions(+)

diff --git a/atr/admin/__init__.py b/atr/admin/__init__.py
index 28a9365..38cf906 100644
--- a/atr/admin/__init__.py
+++ b/atr/admin/__init__.py
@@ -17,6 +17,7 @@
 
 import asyncio
 import collections
+import datetime
 import os
 import pathlib
 import statistics
@@ -34,6 +35,7 @@ import htpy
 import pydantic
 import quart
 import sqlalchemy.orm as orm
+import sqlmodel
 
 import atr.blueprints.admin as admin
 import atr.config as config
@@ -741,6 +743,66 @@ async def tasks_(session: web.Committer) -> str:
     return await template.render("tasks.html")
 
 
[email protected]("/tasks/recent/<int:minutes>")
+async def tasks_recent(session: web.Committer, minutes: int) -> str:
+    """Display tasks from the last N minutes."""
+    if minutes < 1:
+        minutes = 1
+    if minutes > 1440:
+        minutes = 1440
+
+    via = sql.validate_instrumented_attribute
+    cutoff = datetime.datetime.now(datetime.UTC) - 
datetime.timedelta(minutes=minutes)
+
+    async with db.session() as data:
+        statement = sqlmodel.select(sql.Task).where(via(sql.Task.added) >= 
cutoff).order_by(via(sql.Task.added).desc())
+        recent_tasks = (await data.execute(statement)).scalars().all()
+
+    page = htm.Block()
+    minute_word = "minute" if (minutes == 1) else "minutes"
+    page.h1[f"Tasks from the last {minutes} {minute_word}"]
+    task_word = "task" if (len(recent_tasks) == 1) else "tasks"
+    page.p[f"Found {len(recent_tasks)} {task_word}"]
+
+    if recent_tasks:
+        table = htm.Block(htpy.table, classes=".table.table-sm")
+        table.thead(".table-dark")[
+            htpy.tr[
+                htpy.th["ID"],
+                htpy.th["Type"],
+                htpy.th["Status"],
+                htpy.th["Added"],
+                htpy.th["Project"],
+                htpy.th["Version"],
+                htpy.th["Error"],
+            ]
+        ]
+        tbody = htm.Block(htpy.tbody)
+        for task in recent_tasks:
+            error_text = task.error[:50] + "..." if (task.error and 
(len(task.error) > 50)) else (task.error or "")
+            status_class = {
+                sql.TaskStatus.QUEUED: ".table-secondary",
+                sql.TaskStatus.ACTIVE: ".table-info",
+                sql.TaskStatus.COMPLETED: ".table-success",
+                sql.TaskStatus.FAILED: ".table-danger",
+            }.get(task.status, "")
+            tbody.append(
+                htpy.tr(class_=status_class.lstrip(".") if status_class else 
None)[
+                    htpy.td[str(task.id)],
+                    htpy.td[task.task_type.value],
+                    htpy.td[task.status.value],
+                    htpy.td[task.added.strftime("%H:%M:%S") if task.added else 
""],
+                    htpy.td[task.project_name or ""],
+                    htpy.td[task.version_name or ""],
+                    htpy.td[error_text],
+                ]
+            )
+        table.append(tbody.collect())
+        page.append(table.collect())
+
+    return await template.blank(f"Recent Tasks ({minutes}m)", 
content=page.collect())
+
+
 @admin.get("/task-times/<project_name>/<version_name>/<revision_number>")
 async def task_times(
     session: web.Committer, project_name: str, version_name: str, 
revision_number: str
diff --git a/atr/templates/includes/sidebar.html 
b/atr/templates/includes/sidebar.html
index 467f97b..1bd3fae 100644
--- a/atr/templates/includes/sidebar.html
+++ b/atr/templates/includes/sidebar.html
@@ -228,6 +228,10 @@
             <a href="{{ as_url(admin.tasks_) }}"
                {% if request.endpoint == 'atr_admin_tasks_' %}class="active"{% 
endif %}>Background tasks</a>
           </li>
+          <li>
+            <i class="bi bi-clock-history"></i>
+            <a href="{{ as_url(admin.tasks_recent, minutes=5) }}">Recent 
tasks</a>
+          </li>
           <li>
             <i class="bi bi-person-badge"></i>
             <a href="{{ as_url(admin.toggle_view_get) }}"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to