diff --git a/pipekit/repo.py b/pipekit/repo.py index 266f7ad..4dc26f9 100644 --- a/pipekit/repo.py +++ b/pipekit/repo.py @@ -404,7 +404,8 @@ def clear_stale_locks(max_age_hours: int = 24, live_pids: set[int] | None = None def create_run(module_id: int, *, group_run_id: int | None = None) -> int: with db.connect() as c: cur = c.execute( - "INSERT INTO run_log (module_id, group_run_id) VALUES (?, ?)", + "INSERT INTO run_log (module_id, group_run_id, started_at) " + "VALUES (?, ?, datetime('now'))", (module_id, group_run_id), ) return int(cur.lastrowid) @@ -494,6 +495,10 @@ def list_runs(*, module_id: int | None = None, status: str | None = None, params.append(limit) with db.connect() as c: return [dict(r) for r in c.execute( - f"SELECT r.*, m.name AS module_name FROM run_log r " + f"SELECT r.*, m.name AS module_name, " + f"CASE WHEN r.started_at IS NOT NULL AND r.finished_at IS NOT NULL " + f"THEN CAST(ROUND((julianday(r.finished_at) - julianday(r.started_at)) * 86400) AS INTEGER) " + f"ELSE NULL END AS duration_s " + f"FROM run_log r " f"LEFT JOIN module m ON r.module_id=m.id " f"{clause} ORDER BY r.id DESC LIMIT ?", params)] diff --git a/pipekit/web/app.py b/pipekit/web/app.py index a46e4d2..77437d1 100644 --- a/pipekit/web/app.py +++ b/pipekit/web/app.py @@ -29,6 +29,18 @@ _WEB_DIR = Path(__file__).parent _templates = Jinja2Templates(directory=_WEB_DIR / "templates") +def _fmt_duration(seconds) -> str: + if seconds is None: + return "—" + s = int(seconds) + if s < 60: + return f"{s}s" + return f"{s // 60}m {s % 60:02d}s" + + +_templates.env.filters["duration"] = _fmt_duration + + def mount_web(app: FastAPI) -> None: """Attach HTML pages + /static onto a FastAPI app.""" app.mount("/static", StaticFiles(directory=_WEB_DIR / "static"), name="static") diff --git a/pipekit/web/templates/module_detail.html b/pipekit/web/templates/module_detail.html index 29021b0..9f9b0a6 100644 --- a/pipekit/web/templates/module_detail.html +++ b/pipekit/web/templates/module_detail.html @@ -187,12 +187,13 @@
| id | started | status | rows | ||||
|---|---|---|---|---|---|---|---|
| id | started | duration | status | rows | |||
| #{{ r.id }} | -{{ r.started_at }} | +{{ r.started_at or '—' }} | +{{ r.duration_s | duration }} | {{ r.status }} | {{ r.row_count if r.row_count is not none else "—" }} | id | module | started | -finished | +duration | status | rows | error | @@ -33,8 +33,8 @@
| #{{ r.id }} | {{ r.module_name }} | -{{ r.started_at }} | -{{ r.finished_at or '—' }} | +{{ r.started_at or '—' }} | +{{ r.duration_s | duration }} | {{ r.status }} | {{ r.row_count if r.row_count is not none else "—" }} |