mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
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.
This commit is contained in:
parent
d80ec72fe0
commit
f7279610a8
4 changed files with 27 additions and 12 deletions
|
|
@ -2,6 +2,7 @@
|
|||
{% load i18n %}
|
||||
{% load bootstrap_icons %}
|
||||
{% load operations %}
|
||||
{% load tz %}
|
||||
|
||||
{% block title %}{{ job.label }}{% endblock %}
|
||||
|
||||
|
|
@ -45,9 +46,10 @@
|
|||
</span>
|
||||
</dd>
|
||||
{% endif %}
|
||||
<dt class="col-sm-3">{% trans "Created" %}</dt><dd class="col-sm-9">{{ op.created_at|date:"M d H:i:s" }}</dd>
|
||||
{% if op.started_at %}<dt class="col-sm-3">{% trans "Started" %}</dt><dd class="col-sm-9">{{ op.started_at|date:"M d H:i:s" }}</dd>{% endif %}
|
||||
{% if op.finished_at %}<dt class="col-sm-3">{% trans "Finished" %}</dt><dd class="col-sm-9">{{ op.finished_at|date:"M d H:i:s" }}</dd>{% endif %}
|
||||
{% get_current_timezone as TIME_ZONE %}
|
||||
<dt class="col-sm-3">{% blocktrans %}Created ({{ TIME_ZONE }}){% endblocktrans %}</dt><dd class="col-sm-9">{{ op.created_at|date:"Y-m-d H:i:s" }}</dd>
|
||||
{% if op.started_at %}<dt class="col-sm-3">{% trans "Started" %}</dt><dd class="col-sm-9">{{ op.started_at|date:"Y-m-d H:i:s" }}</dd>{% endif %}
|
||||
{% if op.finished_at %}<dt class="col-sm-3">{% trans "Finished" %}</dt><dd class="col-sm-9">{{ op.finished_at|date:"Y-m-d H:i:s" }}</dd>{% endif %}
|
||||
{% if job.result.left_behind %}
|
||||
<dt class="col-sm-3">{% trans "Left behind" %}</dt>
|
||||
<dd class="col-sm-9">
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
<div class="alert alert-warning shadow-sm">
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.user.is_superuser %}
|
||||
|
|
@ -56,7 +57,8 @@
|
|||
<table class="table table-hover table-striped align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="d-none d-md-table-cell">{% trans "Created" %}</th>
|
||||
{% get_current_timezone as TIME_ZONE %}
|
||||
<th scope="col" class="d-none d-md-table-cell">{% blocktrans %}Created ({{ TIME_ZONE }}){% endblocktrans %}</th>
|
||||
<th scope="col">{% trans "Job" %}</th>
|
||||
<th scope="col">{% trans "State" %}</th>
|
||||
<th scope="col" class="d-none d-md-table-cell">{% trans "Resource" %}</th>
|
||||
|
|
@ -66,7 +68,7 @@
|
|||
<tbody>
|
||||
{% for op, row in rows %}
|
||||
<tr>
|
||||
<td class="text-nowrap d-none d-md-table-cell">{{ op.created_at|date:"M d H:i:s" }}</td>
|
||||
<td class="text-nowrap d-none d-md-table-cell">{{ op.created_at|date:"Y-m-d H:i:s" }}</td>
|
||||
<td style="min-width: 10rem;">
|
||||
<a href="{% url 'operations:job' row.id %}">{{ row.label }}</a>
|
||||
{% if op.state in active_states and op.phase %}
|
||||
|
|
@ -75,7 +77,7 @@
|
|||
<div class="small text-body-secondary" title="{{ op.error }}">{{ op.error|truncatechars:80 }}</div>
|
||||
{% endif %}
|
||||
{# below md the hidden columns show here #}
|
||||
<div class="d-md-none small text-body-secondary">{{ row.resource_label|wrap_at_slash }}<br>{{ op.created_at|date:"M d H:i:s" }}{% if request.user.is_superuser %} · {{ row.username }}{% endif %}</div>
|
||||
<div class="d-md-none small text-body-secondary">{{ row.resource_label|wrap_at_slash }}<br>{{ op.created_at|date:"Y-m-d H:i:s" }}{% if request.user.is_superuser %} · {{ row.username }}{% endif %}</div>
|
||||
</td>
|
||||
<td>{% include "operations/state_badge.html" with state=op.state %}</td>
|
||||
<td class="d-none d-md-table-cell">{{ row.resource_label|wrap_at_slash }}</td>
|
||||
|
|
|
|||
|
|
@ -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'<th scope="col" class="d-none d-md-table-cell">{header}</th>', html)
|
||||
narrow = re.search(r'<div class="d-md-none small text-body-secondary">(.*?)</div>', html, re.S).group(1)
|
||||
for text in ('<span class="text-nowrap">wvc-test-vm</span>', "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()
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue