Add run status polling endpoint and update rota run detail view for real-time status updates
This commit is contained in:
@@ -12,6 +12,11 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="title">Rota run for {{ run.rota.name }}</h1>
|
<h1 class="title">Rota run for {{ run.rota.name }}</h1>
|
||||||
<p class="subtitle">Status: {{ run.get_status_display }} ({{ run.status }})</p>
|
<p class="subtitle">Status: {{ run.get_status_display }} ({{ run.status }})</p>
|
||||||
|
<div style="margin-bottom:0.5rem;" id="run-status-container">
|
||||||
|
<div id="run-status" hx-get="{% url 'rota:rota_run_status' run.id %}" hx-trigger="every 3s" hx-swap="outerHTML">
|
||||||
|
<span class="tag">Status: {{ run.get_status_display }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<p>Created: {{ run.created_at|localtime }} started: {{ run.started_at|localtime }} finished: {{ run.finished_at|localtime }}</p>
|
<p>Created: {{ run.created_at|localtime }} started: {{ run.started_at|localtime }} finished: {{ run.finished_at|localtime }}</p>
|
||||||
<p class="mt-2">
|
<p class="mt-2">
|
||||||
<a class="button" href="{% url 'rota:rota_detail' run.rota.id %}">Back to rota</a>
|
<a class="button" href="{% url 'rota:rota_detail' run.rota.id %}">Back to rota</a>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ urlpatterns = [
|
|||||||
path("worker/<int:worker_id>/leaves/delete_all/", views.leave_delete_all, name="leave_delete_all"),
|
path("worker/<int:worker_id>/leaves/delete_all/", views.leave_delete_all, name="leave_delete_all"),
|
||||||
path("worker/<int:worker_id>/regenerate_token/", views.regenerate_worker_token, name="regenerate_worker_token"),
|
path("worker/<int:worker_id>/regenerate_token/", views.regenerate_worker_token, name="regenerate_worker_token"),
|
||||||
path("run/<int:run_id>/", views.rota_run_detail, name="rota_run_detail"),
|
path("run/<int:run_id>/", views.rota_run_detail, name="rota_run_detail"),
|
||||||
|
path("run/<int:run_id>/status/", views.rota_run_status, name="rota_run_status"),
|
||||||
path("run/<int:run_id>/export/html/", views.rota_run_export_html, name="rota_run_export_html"),
|
path("run/<int:run_id>/export/html/", views.rota_run_export_html, name="rota_run_export_html"),
|
||||||
path("run/<int:run_id>/export/download/", views.rota_run_export_download, name="rota_run_export_download"),
|
path("run/<int:run_id>/export/download/", views.rota_run_export_download, name="rota_run_export_download"),
|
||||||
path("rota/<int:rota_id>/export/builder/", views.rota_export_builder, name="rota_export_builder"),
|
path("rota/<int:rota_id>/export/builder/", views.rota_export_builder, name="rota_export_builder"),
|
||||||
|
|||||||
@@ -738,6 +738,40 @@ def rota_run_detail(request, run_id):
|
|||||||
return render(request, "rota/rota_run_detail.html", {"run": run, "result_pretty": result_pretty, "builder_html": builder_html})
|
return render(request, "rota/rota_run_detail.html", {"run": run, "result_pretty": result_pretty, "builder_html": builder_html})
|
||||||
|
|
||||||
|
|
||||||
|
def rota_run_status(request, run_id):
|
||||||
|
"""Return a small HTML fragment describing the run status.
|
||||||
|
|
||||||
|
This endpoint is intended to be polled by HTMX. While the run is
|
||||||
|
still running we return a fragment that contains the polling HTMX
|
||||||
|
attributes so the client will continue to poll. Once the run is
|
||||||
|
finished we return a final fragment (no polling attributes) and
|
||||||
|
include a small script to reload the page so the UI updates.
|
||||||
|
"""
|
||||||
|
from .models import RotaRun
|
||||||
|
|
||||||
|
run = get_object_or_404(RotaRun, pk=run_id)
|
||||||
|
|
||||||
|
# If the run is still pending/running, return a self-updating fragment
|
||||||
|
if run.status in (RotaRun.STATUS_PENDING, RotaRun.STATUS_RUNNING):
|
||||||
|
html = (
|
||||||
|
f'<div id="run-status" hx-get="{reverse("rota:rota_run_status", args=[run.id])}" '
|
||||||
|
'hx-trigger="every 3s" hx-swap="outerHTML">'
|
||||||
|
f'<span class="tag is-info">Status: {run.get_status_display()}</span>'
|
||||||
|
f' <small>started: {run.started_at}</small>'
|
||||||
|
"</div>"
|
||||||
|
)
|
||||||
|
return HttpResponse(html)
|
||||||
|
|
||||||
|
# Finished/failed: return final fragment and reload the page so the
|
||||||
|
# user sees final logs/export without further polling.
|
||||||
|
final_html = (
|
||||||
|
f'<div id="run-status-final"><span class="tag is-success">Status: {run.get_status_display()}</span>'
|
||||||
|
f' <small>finished: {run.finished_at}</small></div>'
|
||||||
|
"<script>window.location.reload();</script>"
|
||||||
|
)
|
||||||
|
return HttpResponse(final_html)
|
||||||
|
|
||||||
|
|
||||||
def rota_run_export_html(request, run_id):
|
def rota_run_export_html(request, run_id):
|
||||||
from .models import RotaRun
|
from .models import RotaRun
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user