From f7279610a81af544740b423f9178f60f05b84f36 Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 26 Oct 2026 10:51:05 +0300 Subject: [PATCH] fix(operations): Jobs dates carry the year and time zone, filters match part of a name Job dates showed no year and no time zone, unlike the Logs page; they now read 2026-10-13 23:04:00 under "Created (time zone)". The host filter matched only a whole host name and the user filter only an exact username; both now ignore case and take the start of a host or any part of a name. --- operations/templates/operations/job.html | 8 +++++--- operations/templates/operations/jobs.html | 10 ++++++---- operations/tests/test_views.py | 14 +++++++++++--- operations/views.py | 7 +++++-- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/operations/templates/operations/job.html b/operations/templates/operations/job.html index 2aa3dfa6..e786b16e 100644 --- a/operations/templates/operations/job.html +++ b/operations/templates/operations/job.html @@ -2,6 +2,7 @@ {% load i18n %} {% load bootstrap_icons %} {% load operations %} +{% load tz %} {% block title %}{{ job.label }}{% endblock %} @@ -45,9 +46,10 @@ {% endif %} -
{% trans "Created" %}
{{ op.created_at|date:"M d H:i:s" }}
- {% if op.started_at %}
{% trans "Started" %}
{{ op.started_at|date:"M d H:i:s" }}
{% endif %} - {% if op.finished_at %}
{% trans "Finished" %}
{{ op.finished_at|date:"M d H:i:s" }}
{% endif %} + {% get_current_timezone as TIME_ZONE %} +
{% blocktrans %}Created ({{ TIME_ZONE }}){% endblocktrans %}
{{ op.created_at|date:"Y-m-d H:i:s" }}
+ {% if op.started_at %}
{% trans "Started" %}
{{ op.started_at|date:"Y-m-d H:i:s" }}
{% endif %} + {% if op.finished_at %}
{% trans "Finished" %}
{{ op.finished_at|date:"Y-m-d H:i:s" }}
{% endif %} {% if job.result.left_behind %}
{% trans "Left behind" %}
diff --git a/operations/templates/operations/jobs.html b/operations/templates/operations/jobs.html index e072cdcb..9114a8de 100644 --- a/operations/templates/operations/jobs.html +++ b/operations/templates/operations/jobs.html @@ -3,6 +3,7 @@ {% load django_bootstrap5 %} {% load bootstrap_icons %} {% load operations %} +{% load tz %} {% block title %}{% trans "Jobs" %}{% endblock %} @@ -14,7 +15,7 @@ {% if worker_unavailable %}
{% bs_icon 'exclamation-triangle' %} {% trans "Worker unavailable, last seen" %} - {% if worker_last_seen %}{{ worker_last_seen|date:"M d H:i:s" }}{% else %}{% trans "never" %}{% endif %} + {% if worker_last_seen %}{{ worker_last_seen|date:"Y-m-d H:i:s" }}{% else %}{% trans "never" %}{% endif %}
{% endif %} {% if request.user.is_superuser %} @@ -56,7 +57,8 @@ - + {% get_current_timezone as TIME_ZONE %} + @@ -66,7 +68,7 @@ {% for op, row in rows %} - + diff --git a/operations/tests/test_views.py b/operations/tests/test_views.py index 44c3b501..e1964b38 100644 --- a/operations/tests/test_views.py +++ b/operations/tests/test_views.py @@ -54,6 +54,13 @@ class JobsPageTestCase(TransactionTestCase): self.assertContains(self.client.get(reverse("operations:jobs"), {"compute": "c"}), link) self.assertNotContains(self.client.get(reverse("operations:jobs"), {"state": "failed"}), link) + def test_host_and_user_filters_match_part_of_the_name(self): + self.client.force_login(self.admin) + link = reverse("operations:job", args=[self.op.pk]) + for filters in ({"compute": "C"}, {"username": "PAGE_U"}): + self.assertContains(self.client.get(reverse("operations:jobs"), filters), link) + self.assertNotContains(self.client.get(reverse("operations:jobs"), {"username": "other"}), link) + def test_resolve_needs_a_superuser_an_outcome_and_a_note(self): jobs.finish(self.op, Outcome(Operation.UNCERTAIN, error="check")) self.client.force_login(self.user) @@ -121,7 +128,8 @@ class JobsPageTestCase(TransactionTestCase): self.client.force_login(self.admin) for response in (self.client.get(reverse("operations:jobs")), self.client.get(reverse("operations:job", args=[self.op.pk]))): - self.assertContains(response, "Oct 13 23:04:00") + self.assertContains(response, "2026-10-13 23:04:00") + self.assertContains(response, f"Created ({django_timezone.get_current_timezone_name()})") self.assertNotContains(response, "2026-10-13T20:04") def test_list_and_detail_refresh_while_a_job_is_active(self): @@ -196,12 +204,12 @@ class JobsPageTestCase(TransactionTestCase): self.client.force_login(self.admin) html = self.client.get(reverse("operations:jobs")).content.decode() # below md only Job and State are columns - for header in ("Created", "Resource", "User"): + for header in (f"Created ({django_timezone.get_current_timezone_name()})", "Resource", "User"): self.assertIn(f'', html) narrow = re.search(r'
(.*?)
', html, re.S).group(1) for text in ('wvc-test-vm', "page_user"): self.assertIn(text, narrow) - self.assertRegex(narrow, r"[A-Z][a-z]{2} \d{2} \d{2}:\d{2}:\d{2}") + self.assertRegex(narrow, r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}") # a plain user's narrow line has no user self.client.force_login(self.user) html = self.client.get(reverse("operations:jobs")).content.decode() diff --git a/operations/views.py b/operations/views.py index 1d98820c..767280dd 100644 --- a/operations/views.py +++ b/operations/views.py @@ -30,9 +30,12 @@ def _get(user, pk): def jobs(request): qs = _visible(request.user) if request.user.is_superuser: + # the host and the user as typed: the start of the host, any part of the name if compute := request.GET.get("compute"): - qs = qs.filter(resource_label__startswith=f"{compute}/") - for field in ("state", "kind", "username"): + qs = qs.filter(resource_label__istartswith=compute) + if username := request.GET.get("username"): + qs = qs.filter(username__icontains=username) + for field in ("state", "kind"): if value := request.GET.get(field): qs = qs.filter(**{field: value}) page = Paginator(qs, 50).get_page(request.GET.get("page"))
{% trans "Created" %}{% blocktrans %}Created ({{ TIME_ZONE }}){% endblocktrans %} {% trans "Job" %} {% trans "State" %} {% trans "Resource" %}
{{ op.created_at|date:"M d H:i:s" }}{{ op.created_at|date:"Y-m-d H:i:s" }} {{ row.label }} {% if op.state in active_states and op.phase %} @@ -75,7 +77,7 @@
{{ op.error|truncatechars:80 }}
{% endif %} {# below md the hidden columns show here #} -
{{ row.resource_label|wrap_at_slash }}
{{ op.created_at|date:"M d H:i:s" }}{% if request.user.is_superuser %} · {{ row.username }}{% endif %}
+
{{ row.resource_label|wrap_at_slash }}
{{ op.created_at|date:"Y-m-d H:i:s" }}{% if request.user.is_superuser %} · {{ row.username }}{% endif %}
{% include "operations/state_badge.html" with state=op.state %} {{ row.resource_label|wrap_at_slash }}{header}