diff --git a/web/src/padelnomics/admin/routes.py b/web/src/padelnomics/admin/routes.py index 1657fe7..c20a49f 100644 --- a/web/src/padelnomics/admin/routes.py +++ b/web/src/padelnomics/admin/routes.py @@ -1434,6 +1434,42 @@ async def scenarios(): current_search=search, current_country=country_filter, current_venue_type=venue_filter, + is_generating=await _is_generating(), + ) + + +@bp.route("/scenarios/results") +@role_required("admin") +async def scenario_results(): + """HTMX partial for scenario results (used by live polling).""" + search = request.args.get("search", "").strip() + country_filter = request.args.get("country", "") + venue_filter = request.args.get("venue_type", "") + + wheres = ["1=1"] + params: list = [] + if search: + wheres.append("(title LIKE ? OR location LIKE ? OR slug LIKE ?)") + params.extend([f"%{search}%", f"%{search}%", f"%{search}%"]) + if country_filter: + wheres.append("country = ?") + params.append(country_filter) + if venue_filter: + wheres.append("venue_type = ?") + params.append(venue_filter) + + where = " AND ".join(wheres) + scenario_list = await fetch_all( + f"SELECT * FROM published_scenarios WHERE {where} ORDER BY created_at DESC LIMIT 500", + tuple(params), + ) + total = await fetch_one("SELECT COUNT(*) as cnt FROM published_scenarios") + + return await render_template( + "admin/partials/scenario_results.html", + scenarios=scenario_list, + total=total["cnt"] if total else 0, + is_generating=await _is_generating(), ) @@ -1683,6 +1719,14 @@ async def _get_article_stats() -> dict: return dict(row) if row else {"total": 0, "live": 0, "scheduled": 0, "draft": 0} +async def _is_generating() -> bool: + """Return True if a generate_articles task is currently pending.""" + row = await fetch_one( + "SELECT COUNT(*) AS cnt FROM tasks WHERE task_type = 'generate_articles' AND status = 'pending'" + ) + return bool(row and row["cnt"] > 0) + + @bp.route("/articles") @role_required("admin") async def articles(): @@ -1712,6 +1756,7 @@ async def articles(): current_template=template_filter, current_language=language_filter, page=page, + is_generating=await _is_generating(), ) @@ -1730,7 +1775,10 @@ async def article_results(): language=language_filter or None, search=search or None, page=page, ) return await render_template( - "admin/partials/article_results.html", articles=article_list, page=page, + "admin/partials/article_results.html", + articles=article_list, + page=page, + is_generating=await _is_generating(), ) diff --git a/web/src/padelnomics/admin/templates/admin/partials/article_results.html b/web/src/padelnomics/admin/templates/admin/partials/article_results.html index 2d95b07..d0ef5d8 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/article_results.html +++ b/web/src/padelnomics/admin/templates/admin/partials/article_results.html @@ -1,3 +1,10 @@ +{% if is_generating %} + +{% endif %} {% if articles %}
diff --git a/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html b/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html new file mode 100644 index 0000000..93dd343 --- /dev/null +++ b/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html @@ -0,0 +1,44 @@ +{% if is_generating %} + +{% endif %} +{% if scenarios %} +
+ + + + + + + + + + + + {% for s in scenarios %} + + + + + + + + + {% endfor %} + +
TitleSlugLocationConfigCreated
{{ s.title }}{{ s.slug }}{{ s.location }}, {{ s.country }}{{ s.venue_type | capitalize }} · {{ s.court_config }}{{ s.created_at[:10] }} + Preview + PDF EN + PDF DE + Edit +
+ + +
+
+{% else %} +

No scenarios match the current filters.

+{% endif %} diff --git a/web/src/padelnomics/admin/templates/admin/scenarios.html b/web/src/padelnomics/admin/templates/admin/scenarios.html index c32270e..6d993fb 100644 --- a/web/src/padelnomics/admin/templates/admin/scenarios.html +++ b/web/src/padelnomics/admin/templates/admin/scenarios.html @@ -51,42 +51,8 @@
- {% if scenarios %} - - - - - - - - - - - - - {% for s in scenarios %} - - - - - - - - - {% endfor %} - -
TitleSlugLocationConfigCreated
{{ s.title }}{{ s.slug }}{{ s.location }}, {{ s.country }}{{ s.venue_type | capitalize }} · {{ s.court_config }}{{ s.created_at[:10] }} - Preview - PDF EN - PDF DE - Edit -
- - -
-
- {% else %} -

No scenarios match the current filters.

- {% endif %} +
+ {% include "admin/partials/scenario_results.html" %} +
{% endblock %}