dj-queue 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dj_queue-0.2.0 → dj_queue-0.2.2}/PKG-INFO +4 -3
- {dj_queue-0.2.0 → dj_queue-0.2.2}/README.md +3 -2
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/admin.py +133 -7
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/apps.py +1 -1
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/dashboard.py +12 -5
- dj_queue-0.2.2/dj_queue/templates/admin/dj_queue/change_form.html +69 -0
- dj_queue-0.2.2/dj_queue/templates/admin/dj_queue/change_list.html +11 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/templates/admin/dj_queue/dashboard.html +47 -33
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/templates/admin/dj_queue/queue_jobs.html +107 -10
- {dj_queue-0.2.0 → dj_queue-0.2.2}/pyproject.toml +1 -1
- {dj_queue-0.2.0 → dj_queue-0.2.2}/LICENSE +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/api.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/backend.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/config.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/contrib/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/contrib/asgi.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/contrib/gunicorn.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/db.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/exceptions.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/hooks.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/log.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/management/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/management/commands/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/management/commands/dj_queue.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/management/commands/dj_queue_health.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/management/commands/dj_queue_prune.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/0001_initial.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/0002_pause_semaphore.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/0003_recurringtask_recurringexecution.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/0004_dashboard.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/models/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/models/jobs.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/models/recurring.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/models/runtime.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/operations/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/operations/cleanup.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/operations/concurrency.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/operations/jobs.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/operations/recurring.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/routers.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/__init__.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/base.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/dispatcher.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/errors.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/interruptible.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/notify.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/pidfile.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/pool.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/procline.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/scheduler.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/supervisor.py +0 -0
- {dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/runtime/worker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dj-queue
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Database-backed task queue backend for Django's django.tasks framework
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -28,6 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
[](https://github.com/coriocactus/dj_queue/actions/workflows/ci.yml)
|
|
30
30
|

|
|
31
|
+
[](https://djangopackages.org/packages/p/dj-queue/)
|
|
31
32
|

|
|
32
33
|

|
|
33
34
|

|
|
@@ -414,8 +415,8 @@ pauses, and semaphores.
|
|
|
414
415
|
When a task raises, `dj_queue` keeps the job and its failed execution row in the
|
|
415
416
|
queue database, including the exception class, message, and traceback.
|
|
416
417
|
|
|
417
|
-
You can retry failed jobs through Django admin, or
|
|
418
|
-
through the operations layer:
|
|
418
|
+
You can retry and discard failed jobs through Django admin, or call the same
|
|
419
|
+
operations directly through the operations layer:
|
|
419
420
|
|
|
420
421
|
```python
|
|
421
422
|
from dj_queue.operations.jobs import discard_failed_job, retry_failed_job
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/coriocactus/dj_queue/actions/workflows/ci.yml)
|
|
4
4
|

|
|
5
|
+
[](https://djangopackages.org/packages/p/dj-queue/)
|
|
5
6
|

|
|
6
7
|

|
|
7
8
|

|
|
@@ -388,8 +389,8 @@ pauses, and semaphores.
|
|
|
388
389
|
When a task raises, `dj_queue` keeps the job and its failed execution row in the
|
|
389
390
|
queue database, including the exception class, message, and traceback.
|
|
390
391
|
|
|
391
|
-
You can retry failed jobs through Django admin, or
|
|
392
|
-
through the operations layer:
|
|
392
|
+
You can retry and discard failed jobs through Django admin, or call the same
|
|
393
|
+
operations directly through the operations layer:
|
|
393
394
|
|
|
394
395
|
```python
|
|
395
396
|
from dj_queue.operations.jobs import discard_failed_job, retry_failed_job
|
|
@@ -29,10 +29,25 @@ from dj_queue.models import (
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class DjQueueFirstAdminSite(admin.AdminSite):
|
|
32
|
+
def _dashboard_app_url(self):
|
|
33
|
+
return reverse("admin:dj_queue_dashboard_changelist", current_app=self.name)
|
|
34
|
+
|
|
32
35
|
def get_app_list(self, request, app_label=None):
|
|
33
36
|
app_list = super().get_app_list(request, app_label=app_label)
|
|
37
|
+
for app in app_list:
|
|
38
|
+
if app["app_label"] == "dj_queue":
|
|
39
|
+
app["app_url"] = self._dashboard_app_url()
|
|
34
40
|
return sorted(app_list, key=lambda app: app["app_label"] != "dj_queue")
|
|
35
41
|
|
|
42
|
+
def app_index(self, request, app_label, extra_context=None):
|
|
43
|
+
if app_label == "dj_queue":
|
|
44
|
+
url = self._dashboard_app_url()
|
|
45
|
+
query = request.GET.urlencode()
|
|
46
|
+
if query:
|
|
47
|
+
url = f"{url}?{query}"
|
|
48
|
+
return HttpResponseRedirect(url)
|
|
49
|
+
return super().app_index(request, app_label, extra_context=extra_context)
|
|
50
|
+
|
|
36
51
|
|
|
37
52
|
admin.site.__class__ = DjQueueFirstAdminSite
|
|
38
53
|
|
|
@@ -64,6 +79,7 @@ class DashboardAdmin(admin.ModelAdmin):
|
|
|
64
79
|
context = {
|
|
65
80
|
**self.admin_site.each_context(request),
|
|
66
81
|
**dashboard.dashboard_context(backend_alias=backend_alias, query_params=request.GET),
|
|
82
|
+
"title": "dj_queue",
|
|
67
83
|
}
|
|
68
84
|
if extra_context:
|
|
69
85
|
context.update(extra_context)
|
|
@@ -96,16 +112,19 @@ class DashboardAdmin(admin.ModelAdmin):
|
|
|
96
112
|
backend_alias = dashboard.resolve_backend_alias(request.GET.get("backend"))
|
|
97
113
|
state = request.GET.get("state", "ready")
|
|
98
114
|
page_number = request.GET.get("page", 1)
|
|
115
|
+
queue_context = dashboard.queue_page_context(
|
|
116
|
+
backend_alias=backend_alias,
|
|
117
|
+
queue_name=queue_name,
|
|
118
|
+
state=state,
|
|
119
|
+
page_number=page_number,
|
|
120
|
+
query_params=request.GET,
|
|
121
|
+
)
|
|
99
122
|
context = {
|
|
100
123
|
**self.admin_site.each_context(request),
|
|
101
|
-
**
|
|
102
|
-
backend_alias=backend_alias,
|
|
103
|
-
queue_name=queue_name,
|
|
104
|
-
state=state,
|
|
105
|
-
page_number=page_number,
|
|
106
|
-
query_params=request.GET,
|
|
107
|
-
),
|
|
124
|
+
**queue_context,
|
|
108
125
|
"job_actions": dashboard.job_actions_for_state(state),
|
|
126
|
+
"title": "dj_queue",
|
|
127
|
+
"subtitle": queue_name,
|
|
109
128
|
}
|
|
110
129
|
return TemplateResponse(request, "admin/dj_queue/queue_jobs.html", context)
|
|
111
130
|
|
|
@@ -175,10 +194,35 @@ class HiddenSidebarAdminMixin:
|
|
|
175
194
|
backend_query_param = "backend"
|
|
176
195
|
backend_filter_field = None
|
|
177
196
|
ignored_filter_params = ()
|
|
197
|
+
change_list_template = "admin/dj_queue/change_list.html"
|
|
198
|
+
change_form_template = "admin/dj_queue/change_form.html"
|
|
178
199
|
|
|
179
200
|
def get_list_filter(self, request):
|
|
180
201
|
return (BackendListFilter, *tuple(super().get_list_filter(request)))
|
|
181
202
|
|
|
203
|
+
def changelist_view(self, request, extra_context=None):
|
|
204
|
+
extra_context = {**(extra_context or {}), "dashboard_url": self._dashboard_url(request)}
|
|
205
|
+
return super().changelist_view(request, extra_context=extra_context)
|
|
206
|
+
|
|
207
|
+
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
|
|
208
|
+
obj = self.get_object(request, object_id) if object_id is not None else None
|
|
209
|
+
if request.method == "POST":
|
|
210
|
+
action = request.POST.get("_djq_object_action")
|
|
211
|
+
if action and obj is not None:
|
|
212
|
+
return self.handle_change_action(request, obj, action)
|
|
213
|
+
|
|
214
|
+
extra_context = {
|
|
215
|
+
**(extra_context or {}),
|
|
216
|
+
"dashboard_url": self._dashboard_url(request),
|
|
217
|
+
"change_actions": self.get_change_actions(request, obj),
|
|
218
|
+
}
|
|
219
|
+
return super().changeform_view(
|
|
220
|
+
request,
|
|
221
|
+
object_id=object_id,
|
|
222
|
+
form_url=form_url,
|
|
223
|
+
extra_context=extra_context,
|
|
224
|
+
)
|
|
225
|
+
|
|
182
226
|
def has_add_permission(self, request):
|
|
183
227
|
return False
|
|
184
228
|
|
|
@@ -239,6 +283,26 @@ class HiddenSidebarAdminMixin:
|
|
|
239
283
|
def _backend_database_alias(self, request):
|
|
240
284
|
return get_database_alias(self._backend_alias(request))
|
|
241
285
|
|
|
286
|
+
def _dashboard_url(self, request):
|
|
287
|
+
return f"{reverse('admin:dj_queue_dashboard_changelist')}?{urlencode({'backend': self._backend_alias(request)})}"
|
|
288
|
+
|
|
289
|
+
def get_change_actions(self, request, obj):
|
|
290
|
+
return ()
|
|
291
|
+
|
|
292
|
+
def handle_change_action(self, request, obj, action):
|
|
293
|
+
return HttpResponseRedirect(request.get_full_path())
|
|
294
|
+
|
|
295
|
+
def _change_url(self, *, object_id, backend_alias):
|
|
296
|
+
url = reverse(
|
|
297
|
+
f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_change",
|
|
298
|
+
args=[object_id],
|
|
299
|
+
)
|
|
300
|
+
return f"{url}?{urlencode({'backend': backend_alias})}"
|
|
301
|
+
|
|
302
|
+
def _changelist_url(self, *, backend_alias):
|
|
303
|
+
url = reverse(f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist")
|
|
304
|
+
return f"{url}?{urlencode({'backend': backend_alias})}"
|
|
305
|
+
|
|
242
306
|
|
|
243
307
|
class JobStatusListFilter(admin.SimpleListFilter):
|
|
244
308
|
title = "status"
|
|
@@ -409,6 +473,39 @@ class JobAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
|
|
|
409
473
|
url = f"{reverse('admin:dj_queue_dashboard_queue', args=[obj.queue_name])}?{urlencode(query)}"
|
|
410
474
|
return format_html('<a href="{}">{}</a>', url, obj.queue_name)
|
|
411
475
|
|
|
476
|
+
def get_change_actions(self, request, obj):
|
|
477
|
+
if obj is None or obj.status != "failed":
|
|
478
|
+
return ()
|
|
479
|
+
return (
|
|
480
|
+
{"name": "retry", "label": "Retry failed job", "css_class": "djq-object-action-retry"},
|
|
481
|
+
{
|
|
482
|
+
"name": "discard",
|
|
483
|
+
"label": "Discard failed job",
|
|
484
|
+
"css_class": "djq-object-action-discard",
|
|
485
|
+
},
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
def handle_change_action(self, request, obj, action):
|
|
489
|
+
if obj.status != "failed":
|
|
490
|
+
self.message_user(request, "This job is not failed", level=messages.ERROR)
|
|
491
|
+
return HttpResponseRedirect(
|
|
492
|
+
self._change_url(object_id=obj.pk, backend_alias=obj.backend_name)
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
if action == "retry":
|
|
496
|
+
obj.failed_execution.retry()
|
|
497
|
+
self.message_user(request, "Retried failed job", level=messages.SUCCESS)
|
|
498
|
+
return HttpResponseRedirect(
|
|
499
|
+
self._change_url(object_id=obj.pk, backend_alias=obj.backend_name)
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
if action == "discard":
|
|
503
|
+
obj.failed_execution.discard()
|
|
504
|
+
self.message_user(request, "Discarded failed job", level=messages.SUCCESS)
|
|
505
|
+
return HttpResponseRedirect(self._changelist_url(backend_alias=obj.backend_name))
|
|
506
|
+
|
|
507
|
+
return HttpResponseRedirect(self._change_url(object_id=obj.pk, backend_alias=obj.backend_name))
|
|
508
|
+
|
|
412
509
|
|
|
413
510
|
@admin.register(FailedExecution)
|
|
414
511
|
class FailedExecutionAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
|
|
@@ -436,6 +533,35 @@ class FailedExecutionAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
|
|
|
436
533
|
discarded += execution.discard()
|
|
437
534
|
self.message_user(request, f"Discarded {discarded} failed jobs", level=messages.SUCCESS)
|
|
438
535
|
|
|
536
|
+
def get_change_actions(self, request, obj):
|
|
537
|
+
if obj is None:
|
|
538
|
+
return ()
|
|
539
|
+
return (
|
|
540
|
+
{"name": "retry", "label": "Retry failed job", "css_class": "djq-object-action-retry"},
|
|
541
|
+
{
|
|
542
|
+
"name": "discard",
|
|
543
|
+
"label": "Discard failed job",
|
|
544
|
+
"css_class": "djq-object-action-discard",
|
|
545
|
+
},
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
def handle_change_action(self, request, obj, action):
|
|
549
|
+
backend_alias = obj.job.backend_name
|
|
550
|
+
|
|
551
|
+
if action == "retry":
|
|
552
|
+
job_id = obj.job_id
|
|
553
|
+
obj.retry()
|
|
554
|
+
self.message_user(request, "Retried failed job", level=messages.SUCCESS)
|
|
555
|
+
url = reverse("admin:dj_queue_job_change", args=[job_id])
|
|
556
|
+
return HttpResponseRedirect(f"{url}?{urlencode({'backend': backend_alias})}")
|
|
557
|
+
|
|
558
|
+
if action == "discard":
|
|
559
|
+
obj.discard()
|
|
560
|
+
self.message_user(request, "Discarded failed job", level=messages.SUCCESS)
|
|
561
|
+
return HttpResponseRedirect(self._changelist_url(backend_alias=backend_alias))
|
|
562
|
+
|
|
563
|
+
return HttpResponseRedirect(self._change_url(object_id=obj.pk, backend_alias=backend_alias))
|
|
564
|
+
|
|
439
565
|
|
|
440
566
|
@admin.register(Process)
|
|
441
567
|
class ProcessAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
|
|
@@ -550,7 +550,7 @@ def _summary_cards(*, backend_alias, queue_rows, process_rows, recurring_rows, s
|
|
|
550
550
|
"detail": f"{live_processes} live, {stale_processes} stale",
|
|
551
551
|
},
|
|
552
552
|
{
|
|
553
|
-
"label": "control
|
|
553
|
+
"label": "control-plane",
|
|
554
554
|
"value": len(recurring_rows) + len(semaphore_rows),
|
|
555
555
|
"detail": f"{len(recurring_rows)} recurring and {len(semaphore_rows)} semaphores",
|
|
556
556
|
},
|
|
@@ -962,6 +962,7 @@ def _overview_headers(
|
|
|
962
962
|
explicit_sort=explicit_sort,
|
|
963
963
|
page_param=page_param,
|
|
964
964
|
anchor=anchor,
|
|
965
|
+
preserve_anchor=True,
|
|
965
966
|
)
|
|
966
967
|
|
|
967
968
|
|
|
@@ -974,11 +975,12 @@ def _queue_page_headers(*, state, query_params, sort, explicit_sort, page_param,
|
|
|
974
975
|
explicit_sort=explicit_sort,
|
|
975
976
|
page_param=page_param,
|
|
976
977
|
anchor=anchor,
|
|
978
|
+
preserve_anchor=False,
|
|
977
979
|
)
|
|
978
980
|
|
|
979
981
|
|
|
980
982
|
def _sortable_headers(
|
|
981
|
-
*, fields, query_params, sort_param, sort, explicit_sort, page_param, anchor
|
|
983
|
+
*, fields, query_params, sort_param, sort, explicit_sort, page_param, anchor, preserve_anchor
|
|
982
984
|
):
|
|
983
985
|
sort_fields = _parse_sort_fields(sort) if explicit_sort else ()
|
|
984
986
|
|
|
@@ -1021,6 +1023,7 @@ def _sortable_headers(
|
|
|
1021
1023
|
sort_value=primary_sort,
|
|
1022
1024
|
page_param=page_param,
|
|
1023
1025
|
anchor=anchor,
|
|
1026
|
+
preserve_anchor=preserve_anchor,
|
|
1024
1027
|
)
|
|
1025
1028
|
toggle_url = (
|
|
1026
1029
|
_overview_sort_url(
|
|
@@ -1029,6 +1032,7 @@ def _sortable_headers(
|
|
|
1029
1032
|
sort_value=toggle_sort,
|
|
1030
1033
|
page_param=page_param,
|
|
1031
1034
|
anchor=anchor,
|
|
1035
|
+
preserve_anchor=preserve_anchor,
|
|
1032
1036
|
)
|
|
1033
1037
|
if is_sorted
|
|
1034
1038
|
else primary_url
|
|
@@ -1040,6 +1044,7 @@ def _sortable_headers(
|
|
|
1040
1044
|
sort_value=remove_sort,
|
|
1041
1045
|
page_param=page_param,
|
|
1042
1046
|
anchor=anchor,
|
|
1047
|
+
preserve_anchor=preserve_anchor,
|
|
1043
1048
|
)
|
|
1044
1049
|
if is_sorted
|
|
1045
1050
|
else None
|
|
@@ -1073,7 +1078,9 @@ def _queue_result_count_text(*, page_obj, total_count):
|
|
|
1073
1078
|
return f"{page_obj.start_index()}-{page_obj.end_index()} of {total_count} jobs"
|
|
1074
1079
|
|
|
1075
1080
|
|
|
1076
|
-
def _overview_sort_url(
|
|
1081
|
+
def _overview_sort_url(
|
|
1082
|
+
*, query_params, sort_param, sort_value, page_param, anchor, preserve_anchor
|
|
1083
|
+
):
|
|
1077
1084
|
params = query_params.copy()
|
|
1078
1085
|
if sort_value:
|
|
1079
1086
|
params[sort_param] = sort_value
|
|
@@ -1082,8 +1089,8 @@ def _overview_sort_url(*, query_params, sort_param, sort_value, page_param, anch
|
|
|
1082
1089
|
params.pop(page_param, None)
|
|
1083
1090
|
url = params.urlencode() if hasattr(params, "urlencode") else urlencode(params, doseq=True)
|
|
1084
1091
|
if not url:
|
|
1085
|
-
return f"?#{anchor}"
|
|
1086
|
-
return f"?{url}#{anchor}"
|
|
1092
|
+
return f"?#{anchor}" if preserve_anchor else "?"
|
|
1093
|
+
return f"?{url}#{anchor}" if preserve_anchor else f"?{url}"
|
|
1087
1094
|
|
|
1088
1095
|
|
|
1089
1096
|
def _queue_rows(*, backend_alias, now, process_cutoff):
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{% extends "admin/change_form.html" %}
|
|
2
|
+
|
|
3
|
+
{% load i18n admin_urls %}
|
|
4
|
+
|
|
5
|
+
{% block extrastyle %}
|
|
6
|
+
{{ block.super }}
|
|
7
|
+
<style>
|
|
8
|
+
.submit-row form {
|
|
9
|
+
display: inline;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.submit-row .djq-object-action {
|
|
13
|
+
border: none;
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
min-height: 2.1875rem;
|
|
16
|
+
padding: 0.625rem 0.9375rem;
|
|
17
|
+
color: var(--button-fg);
|
|
18
|
+
font-size: 0.75rem;
|
|
19
|
+
line-height: 0.9375rem;
|
|
20
|
+
text-transform: uppercase;
|
|
21
|
+
letter-spacing: 0.5px;
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.submit-row .djq-object-action-retry {
|
|
26
|
+
background: var(--button-bg);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.submit-row .djq-object-action-retry:hover,
|
|
30
|
+
.submit-row .djq-object-action-retry:focus {
|
|
31
|
+
background: var(--button-hover-bg);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.submit-row .djq-object-action-discard {
|
|
35
|
+
background: var(--delete-button-bg);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.submit-row .djq-object-action-discard:hover,
|
|
39
|
+
.submit-row .djq-object-action-discard:focus {
|
|
40
|
+
background: var(--delete-button-hover-bg);
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
43
|
+
{% endblock extrastyle %}
|
|
44
|
+
|
|
45
|
+
{% block breadcrumbs %}
|
|
46
|
+
<div class="breadcrumbs">
|
|
47
|
+
<a href='{% url "admin:index" %}'>{% translate "Home" %}</a>
|
|
48
|
+
› <a href="{{ dashboard_url }}">dj_queue</a>
|
|
49
|
+
› {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
|
|
50
|
+
› {% if add %}{% blocktranslate with name=opts.verbose_name %}Add {{ name }}{% endblocktranslate %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
|
|
51
|
+
</div>
|
|
52
|
+
{% endblock breadcrumbs %}
|
|
53
|
+
|
|
54
|
+
{% block object-tools %}{% endblock object-tools %}
|
|
55
|
+
|
|
56
|
+
{% block submit_buttons_top %}{% endblock submit_buttons_top %}
|
|
57
|
+
|
|
58
|
+
{% block submit_buttons_bottom %}
|
|
59
|
+
{% if change_actions %}
|
|
60
|
+
<div class="submit-row">
|
|
61
|
+
{% for action in change_actions %}
|
|
62
|
+
<form method="post" action="{{ request.get_full_path }}">
|
|
63
|
+
{% csrf_token %}
|
|
64
|
+
<button type="submit" name="_djq_object_action" value="{{ action.name }}" class="djq-object-action {{ action.css_class }}">{{ action.label }}</button>
|
|
65
|
+
</form>
|
|
66
|
+
{% endfor %}
|
|
67
|
+
</div>
|
|
68
|
+
{% endif %}
|
|
69
|
+
{% endblock submit_buttons_bottom %}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{% extends "admin/change_list.html" %}
|
|
2
|
+
|
|
3
|
+
{% load i18n %}
|
|
4
|
+
|
|
5
|
+
{% block breadcrumbs %}
|
|
6
|
+
<div class="breadcrumbs">
|
|
7
|
+
<a href='{% url "admin:index" %}'>{% translate "Home" %}</a>
|
|
8
|
+
› <a href="{{ dashboard_url }}">dj_queue</a>
|
|
9
|
+
› {{ cl.opts.verbose_name_plural|capfirst }}
|
|
10
|
+
</div>
|
|
11
|
+
{% endblock breadcrumbs %}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/changelists.css' %}">
|
|
8
8
|
<style>
|
|
9
9
|
#content-main.djq-dashboard {
|
|
10
|
+
--djq-status-live-fg: #0b6b2d;
|
|
11
|
+
--djq-status-stale-fg: #8a4b00;
|
|
10
12
|
width: 100%;
|
|
11
13
|
max-width: 100%;
|
|
12
14
|
min-width: 0;
|
|
@@ -16,6 +18,18 @@
|
|
|
16
18
|
box-sizing: border-box;
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
@media (prefers-color-scheme: dark) {
|
|
22
|
+
html:not([data-theme="light"]) #content-main.djq-dashboard {
|
|
23
|
+
--djq-status-live-fg: #7ad7a2;
|
|
24
|
+
--djq-status-stale-fg: #ffbf69;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
html[data-theme="dark"] #content-main.djq-dashboard {
|
|
29
|
+
--djq-status-live-fg: #7ad7a2;
|
|
30
|
+
--djq-status-stale-fg: #ffbf69;
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
.djq-hero,
|
|
20
34
|
.djq-summary-grid,
|
|
21
35
|
.djq-section {
|
|
@@ -30,8 +44,8 @@
|
|
|
30
44
|
display: grid;
|
|
31
45
|
gap: 1rem;
|
|
32
46
|
padding: 1.25rem;
|
|
33
|
-
border: 1px solid
|
|
34
|
-
background:
|
|
47
|
+
border: 1px solid var(--hairline-color);
|
|
48
|
+
background: var(--darkened-bg);
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
.djq-hero-main {
|
|
@@ -43,7 +57,7 @@
|
|
|
43
57
|
p.djq-eyebrow {
|
|
44
58
|
padding: 0;
|
|
45
59
|
margin: 0;
|
|
46
|
-
color:
|
|
60
|
+
color: var(--link-fg);
|
|
47
61
|
font-size: 0.78rem;
|
|
48
62
|
font-weight: 700;
|
|
49
63
|
letter-spacing: 0.08em;
|
|
@@ -60,7 +74,7 @@
|
|
|
60
74
|
max-width: 44rem;
|
|
61
75
|
padding: 0;
|
|
62
76
|
margin: 0;
|
|
63
|
-
color:
|
|
77
|
+
color: var(--body-quiet-color);
|
|
64
78
|
font-size: 0.95rem;
|
|
65
79
|
line-height: 1.5;
|
|
66
80
|
}
|
|
@@ -69,8 +83,8 @@
|
|
|
69
83
|
display: grid;
|
|
70
84
|
gap: 0.9rem;
|
|
71
85
|
padding: 1rem;
|
|
72
|
-
border: 1px solid
|
|
73
|
-
background:
|
|
86
|
+
border: 1px solid var(--hairline-color);
|
|
87
|
+
background: var(--body-bg);
|
|
74
88
|
min-width: 0;
|
|
75
89
|
}
|
|
76
90
|
|
|
@@ -88,7 +102,7 @@
|
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
.djq-backend-switch label {
|
|
91
|
-
color:
|
|
105
|
+
color: var(--link-selected-fg);
|
|
92
106
|
font-size: 0.78rem;
|
|
93
107
|
font-weight: 700;
|
|
94
108
|
letter-spacing: 0.06em;
|
|
@@ -107,7 +121,7 @@
|
|
|
107
121
|
p.djq-backend-caption {
|
|
108
122
|
padding: 0;
|
|
109
123
|
margin: 0;
|
|
110
|
-
color:
|
|
124
|
+
color: var(--body-quiet-color);
|
|
111
125
|
font-size: 0.86rem;
|
|
112
126
|
line-height: 1.45;
|
|
113
127
|
}
|
|
@@ -126,7 +140,7 @@
|
|
|
126
140
|
|
|
127
141
|
.djq-backend-facts dt {
|
|
128
142
|
margin: 0;
|
|
129
|
-
color:
|
|
143
|
+
color: var(--body-quiet-color);
|
|
130
144
|
font-size: 0.76rem;
|
|
131
145
|
font-weight: 700;
|
|
132
146
|
letter-spacing: 0.06em;
|
|
@@ -135,7 +149,7 @@
|
|
|
135
149
|
|
|
136
150
|
.djq-backend-facts dd {
|
|
137
151
|
margin: 0.2rem 0 0;
|
|
138
|
-
color:
|
|
152
|
+
color: var(--body-fg);
|
|
139
153
|
font-size: 0.95rem;
|
|
140
154
|
line-height: 1.3;
|
|
141
155
|
word-break: break-word;
|
|
@@ -143,8 +157,8 @@
|
|
|
143
157
|
|
|
144
158
|
.djq-raw-panel {
|
|
145
159
|
padding: 0.95rem 1rem;
|
|
146
|
-
border: 1px solid
|
|
147
|
-
background:
|
|
160
|
+
border: 1px solid var(--hairline-color);
|
|
161
|
+
background: var(--body-bg);
|
|
148
162
|
min-width: 0;
|
|
149
163
|
}
|
|
150
164
|
|
|
@@ -182,7 +196,7 @@
|
|
|
182
196
|
.djq-raw-group h3 {
|
|
183
197
|
padding: 0;
|
|
184
198
|
margin: 0;
|
|
185
|
-
color:
|
|
199
|
+
color: var(--body-quiet-color);
|
|
186
200
|
font-size: 0.78rem;
|
|
187
201
|
font-weight: 700;
|
|
188
202
|
letter-spacing: 0.08em;
|
|
@@ -232,8 +246,8 @@
|
|
|
232
246
|
}
|
|
233
247
|
|
|
234
248
|
.djq-summary-card {
|
|
235
|
-
border: 1px solid
|
|
236
|
-
background:
|
|
249
|
+
border: 1px solid var(--hairline-color);
|
|
250
|
+
background: var(--body-bg);
|
|
237
251
|
min-width: 0;
|
|
238
252
|
}
|
|
239
253
|
|
|
@@ -250,12 +264,12 @@
|
|
|
250
264
|
font-size: 1.7rem;
|
|
251
265
|
font-weight: 700;
|
|
252
266
|
line-height: 1.1;
|
|
253
|
-
color:
|
|
267
|
+
color: var(--body-fg);
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
.djq-summary-detail {
|
|
257
271
|
margin-top: 0.35rem;
|
|
258
|
-
color:
|
|
272
|
+
color: var(--body-quiet-color);
|
|
259
273
|
font-size: 0.88rem;
|
|
260
274
|
}
|
|
261
275
|
|
|
@@ -276,18 +290,18 @@
|
|
|
276
290
|
display: block;
|
|
277
291
|
width: 100%;
|
|
278
292
|
padding: 0.5rem;
|
|
279
|
-
background:
|
|
280
|
-
color:
|
|
293
|
+
background: var(--primary);
|
|
294
|
+
color: var(--primary-fg);
|
|
281
295
|
box-sizing: border-box;
|
|
282
296
|
}
|
|
283
297
|
|
|
284
298
|
.djq-section-copy {
|
|
285
299
|
margin: 0;
|
|
286
300
|
padding: 0.5rem;
|
|
287
|
-
color:
|
|
301
|
+
color: var(--body-quiet-color);
|
|
288
302
|
font-size: 0.9rem;
|
|
289
303
|
line-height: 1.45;
|
|
290
|
-
border-bottom: 1px solid
|
|
304
|
+
border-bottom: 1px solid var(--hairline-color);
|
|
291
305
|
}
|
|
292
306
|
|
|
293
307
|
.djq-table-wrap {
|
|
@@ -354,7 +368,7 @@
|
|
|
354
368
|
}
|
|
355
369
|
|
|
356
370
|
.djq-process-row-group {
|
|
357
|
-
background:
|
|
371
|
+
background: var(--selected-bg);
|
|
358
372
|
}
|
|
359
373
|
|
|
360
374
|
.djq-process-row-child th:first-child {
|
|
@@ -369,25 +383,25 @@
|
|
|
369
383
|
top: 0.7rem;
|
|
370
384
|
bottom: 0.7rem;
|
|
371
385
|
width: 2px;
|
|
372
|
-
background:
|
|
386
|
+
background: var(--border-color);
|
|
373
387
|
}
|
|
374
388
|
|
|
375
389
|
.djq-process-meta {
|
|
376
390
|
display: block;
|
|
377
391
|
margin-top: 0.15rem;
|
|
378
|
-
color:
|
|
392
|
+
color: var(--body-quiet-color);
|
|
379
393
|
font-size: 0.78rem;
|
|
380
394
|
font-weight: 400;
|
|
381
395
|
white-space: normal;
|
|
382
396
|
}
|
|
383
397
|
|
|
384
398
|
.djq-status-live {
|
|
385
|
-
color:
|
|
399
|
+
color: var(--djq-status-live-fg);
|
|
386
400
|
font-weight: 700;
|
|
387
401
|
}
|
|
388
402
|
|
|
389
403
|
.djq-status-stale {
|
|
390
|
-
color:
|
|
404
|
+
color: var(--djq-status-stale-fg);
|
|
391
405
|
font-weight: 700;
|
|
392
406
|
}
|
|
393
407
|
|
|
@@ -416,7 +430,7 @@
|
|
|
416
430
|
.djq-empty {
|
|
417
431
|
margin: 0;
|
|
418
432
|
padding: 1rem;
|
|
419
|
-
color:
|
|
433
|
+
color: var(--body-quiet-color);
|
|
420
434
|
font-size: 0.86rem;
|
|
421
435
|
line-height: 1.45;
|
|
422
436
|
}
|
|
@@ -796,9 +810,9 @@
|
|
|
796
810
|
<p>Job-centric rows scoped to the selected backend where possible.</p>
|
|
797
811
|
</div>
|
|
798
812
|
<div class="djq-raw-links">
|
|
799
|
-
<a href="{% url 'admin:dj_queue_job_changelist' %}?backend={{ backend_alias }}">
|
|
800
|
-
<a href="{% url 'admin:dj_queue_failedexecution_changelist' %}?backend={{ backend_alias }}">
|
|
801
|
-
<a href="{% url 'admin:dj_queue_pause_changelist' %}?backend={{ backend_alias }}">
|
|
813
|
+
<a href="{% url 'admin:dj_queue_job_changelist' %}?backend={{ backend_alias }}">Jobs</a>
|
|
814
|
+
<a href="{% url 'admin:dj_queue_failedexecution_changelist' %}?backend={{ backend_alias }}">Failed executions</a>
|
|
815
|
+
<a href="{% url 'admin:dj_queue_pause_changelist' %}?backend={{ backend_alias }}">Pauses</a>
|
|
802
816
|
</div>
|
|
803
817
|
</div>
|
|
804
818
|
|
|
@@ -808,9 +822,9 @@
|
|
|
808
822
|
<p>Control-plane rows scoped by the selected backend's queue database alias.</p>
|
|
809
823
|
</div>
|
|
810
824
|
<div class="djq-raw-links">
|
|
811
|
-
<a href="{% url 'admin:dj_queue_process_changelist' %}?backend={{ backend_alias }}">
|
|
812
|
-
<a href="{% url 'admin:dj_queue_recurringtask_changelist' %}?backend={{ backend_alias }}">
|
|
813
|
-
<a href="{% url 'admin:dj_queue_semaphore_changelist' %}?backend={{ backend_alias }}">
|
|
825
|
+
<a href="{% url 'admin:dj_queue_process_changelist' %}?backend={{ backend_alias }}">Processes</a>
|
|
826
|
+
<a href="{% url 'admin:dj_queue_recurringtask_changelist' %}?backend={{ backend_alias }}">Recurring tasks</a>
|
|
827
|
+
<a href="{% url 'admin:dj_queue_semaphore_changelist' %}?backend={{ backend_alias }}">Semaphores</a>
|
|
814
828
|
</div>
|
|
815
829
|
</div>
|
|
816
830
|
</div>
|
|
@@ -6,6 +6,29 @@
|
|
|
6
6
|
{{ block.super }}
|
|
7
7
|
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/changelists.css' %}">
|
|
8
8
|
<style>
|
|
9
|
+
#content-main {
|
|
10
|
+
--djq-tab-selected-bg: var(--primary);
|
|
11
|
+
--djq-tab-selected-border: var(--primary);
|
|
12
|
+
--djq-tab-selected-fg: var(--primary-fg);
|
|
13
|
+
--djq-tab-selected-count-fg: var(--breadcrumbs-link-fg);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@media (prefers-color-scheme: dark) {
|
|
17
|
+
html:not([data-theme="light"]) #content-main {
|
|
18
|
+
--djq-tab-selected-bg: var(--selected-row);
|
|
19
|
+
--djq-tab-selected-border: var(--link-selected-fg);
|
|
20
|
+
--djq-tab-selected-fg: var(--body-fg);
|
|
21
|
+
--djq-tab-selected-count-fg: var(--body-quiet-color);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
html[data-theme="dark"] #content-main {
|
|
26
|
+
--djq-tab-selected-bg: var(--selected-row);
|
|
27
|
+
--djq-tab-selected-border: var(--link-selected-fg);
|
|
28
|
+
--djq-tab-selected-fg: var(--body-fg);
|
|
29
|
+
--djq-tab-selected-count-fg: var(--body-quiet-color);
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
#toolbar .queue-toolbar-row,
|
|
10
33
|
#toolbar .queue-toolbar-meta,
|
|
11
34
|
#toolbar .queue-toolbar-links,
|
|
@@ -78,12 +101,71 @@
|
|
|
78
101
|
margin-top: 0.5rem;
|
|
79
102
|
}
|
|
80
103
|
|
|
81
|
-
.queue-state-tabs {
|
|
82
|
-
|
|
104
|
+
.toplinks.queue-state-tabs {
|
|
105
|
+
gap: 1rem;
|
|
106
|
+
margin-top: 0.75rem;
|
|
107
|
+
padding: 0.45rem;
|
|
108
|
+
border: 1px solid var(--hairline-color);
|
|
109
|
+
background: var(--darkened-bg);
|
|
83
110
|
}
|
|
84
111
|
|
|
85
|
-
.queue-state-
|
|
86
|
-
|
|
112
|
+
.queue-state-tab {
|
|
113
|
+
display: inline-flex;
|
|
114
|
+
gap: 0.4rem;
|
|
115
|
+
align-items: center;
|
|
116
|
+
min-height: 2.15rem;
|
|
117
|
+
padding: 0 0.9rem;
|
|
118
|
+
border: 1px solid var(--border-color);
|
|
119
|
+
border-radius: 999px;
|
|
120
|
+
background: var(--body-bg);
|
|
121
|
+
color: var(--link-fg);
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
text-decoration: none;
|
|
124
|
+
transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#changelist .queue-state-tabs a.queue-state-tab,
|
|
128
|
+
#changelist .queue-state-tabs a.queue-state-tab:hover,
|
|
129
|
+
#changelist .queue-state-tabs a.queue-state-tab:focus,
|
|
130
|
+
#changelist .queue-state-tabs a.queue-state-tab:visited {
|
|
131
|
+
text-decoration: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.queue-state-tab:not(.queue-state-tab-current):hover,
|
|
135
|
+
.queue-state-tab:not(.queue-state-tab-current):focus {
|
|
136
|
+
background: var(--selected-bg);
|
|
137
|
+
border-color: var(--primary);
|
|
138
|
+
color: var(--link-hover-color);
|
|
139
|
+
text-decoration: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.queue-state-tab-current {
|
|
143
|
+
background: var(--djq-tab-selected-bg);
|
|
144
|
+
border-color: var(--djq-tab-selected-border);
|
|
145
|
+
color: var(--djq-tab-selected-fg);
|
|
146
|
+
box-shadow: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.queue-state-tab-current:hover,
|
|
150
|
+
.queue-state-tab-current:focus {
|
|
151
|
+
background: var(--djq-tab-selected-bg);
|
|
152
|
+
border-color: var(--djq-tab-selected-border);
|
|
153
|
+
color: var(--djq-tab-selected-fg);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.queue-state-tab-count {
|
|
157
|
+
color: var(--body-quiet-color);
|
|
158
|
+
font-size: 0.82rem;
|
|
159
|
+
font-weight: 700;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.queue-state-tab-current .queue-state-tab-count {
|
|
163
|
+
color: var(--djq-tab-selected-count-fg);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.queue-state-tab-current:hover .queue-state-tab-count,
|
|
167
|
+
.queue-state-tab-current:focus .queue-state-tab-count {
|
|
168
|
+
color: var(--djq-tab-selected-count-fg);
|
|
87
169
|
}
|
|
88
170
|
|
|
89
171
|
#result_list {
|
|
@@ -104,15 +186,22 @@
|
|
|
104
186
|
{% block breadcrumbs %}
|
|
105
187
|
<div class="breadcrumbs">
|
|
106
188
|
<a href="{% url 'admin:index' %}">Home</a>
|
|
107
|
-
› <a href="{% url 'admin:dj_queue_dashboard_changelist' %}?backend={{ backend_alias }}">
|
|
189
|
+
› <a href="{% url 'admin:dj_queue_dashboard_changelist' %}?backend={{ backend_alias }}">dj_queue</a>
|
|
190
|
+
› <a href="{% url 'admin:dj_queue_dashboard_changelist' %}?backend={{ backend_alias }}#queue-summary">queues</a>
|
|
108
191
|
› {{ queue_name }}
|
|
109
192
|
</div>
|
|
110
193
|
{% endblock breadcrumbs %}
|
|
111
194
|
|
|
112
195
|
{% block content_title %}
|
|
113
|
-
<h1>
|
|
196
|
+
<h1>
|
|
197
|
+
<a href="{% url 'admin:dj_queue_dashboard_changelist' %}?backend={{ backend_alias }}">dj_queue</a>
|
|
198
|
+
› <a href="{% url 'admin:dj_queue_dashboard_changelist' %}?backend={{ backend_alias }}#queue-summary">queues</a>
|
|
199
|
+
› {{ queue_name }}
|
|
200
|
+
</h1>
|
|
114
201
|
{% endblock content_title %}
|
|
115
202
|
|
|
203
|
+
{% block content_subtitle %}{% endblock content_subtitle %}
|
|
204
|
+
|
|
116
205
|
{% block content %}
|
|
117
206
|
<div id="content-main">
|
|
118
207
|
<div class="module" id="changelist">
|
|
@@ -150,12 +239,18 @@
|
|
|
150
239
|
{% endif %}
|
|
151
240
|
</div>
|
|
152
241
|
|
|
153
|
-
<div class="toplinks queue-state-tabs">
|
|
242
|
+
<div class="toplinks queue-state-tabs" aria-label="Job state navigation">
|
|
154
243
|
{% for tab in state_tabs %}
|
|
155
244
|
{% if tab.selected %}
|
|
156
|
-
<span class="queue-state-
|
|
245
|
+
<span class="queue-state-tab queue-state-tab-current" aria-current="page">
|
|
246
|
+
<span>{{ tab.label }}</span>
|
|
247
|
+
<span class="queue-state-tab-count">{{ tab.count }}</span>
|
|
248
|
+
</span>
|
|
157
249
|
{% else %}
|
|
158
|
-
<a href="{% url 'admin:dj_queue_dashboard_queue' queue_name %}?backend={{ backend_alias }}&state={{ tab.name }}">
|
|
250
|
+
<a class="queue-state-tab" href="{% url 'admin:dj_queue_dashboard_queue' queue_name %}?backend={{ backend_alias }}&state={{ tab.name }}">
|
|
251
|
+
<span>{{ tab.label }}</span>
|
|
252
|
+
<span class="queue-state-tab-count">{{ tab.count }}</span>
|
|
253
|
+
</a>
|
|
159
254
|
{% endif %}
|
|
160
255
|
{% endfor %}
|
|
161
256
|
</div>
|
|
@@ -212,7 +307,9 @@
|
|
|
212
307
|
{% if job_actions %}
|
|
213
308
|
<td class="action-checkbox"><input type="checkbox" class="action-select" name="job_ids" value="{{ job.id }}"></td>
|
|
214
309
|
{% endif %}
|
|
215
|
-
<th scope="row"
|
|
310
|
+
<th scope="row">
|
|
311
|
+
<a href="{% url 'admin:dj_queue_job_change' job.id %}?backend={{ backend_alias }}"><code>{{ job.id }}</code></a>
|
|
312
|
+
</th>
|
|
216
313
|
<td>{{ job.task_path }}</td>
|
|
217
314
|
<td>{{ job.priority }}</td>
|
|
218
315
|
<td>{{ job.created_at|date:"Y-m-d H:i:s" }}</td>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dj_queue-0.2.0 → dj_queue-0.2.2}/dj_queue/migrations/0003_recurringtask_recurringexecution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|