mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-18 05:28:16 -06:00
14729 exec detail and common view
This commit is contained in:
parent
cf56066944
commit
ddb7ec3f46
@ -59,10 +59,6 @@ class BackgroundTaskTable(BaseTable):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return repr(e)
|
return repr(e)
|
||||||
|
|
||||||
def __init__(self, queue_index, *args, **kwargs):
|
|
||||||
self.queue_index = queue_index
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class WorkerTable(BaseTable):
|
class WorkerTable(BaseTable):
|
||||||
name = tables.Column(verbose_name=_("Name"))
|
name = tables.Column(verbose_name=_("Name"))
|
||||||
|
@ -14,6 +14,8 @@ from django.views.generic import View
|
|||||||
from netbox.config import get_config, PARAMS
|
from netbox.config import get_config, PARAMS
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from netbox.views.generic.base import BaseObjectView
|
from netbox.views.generic.base import BaseObjectView
|
||||||
|
from netbox.views.generic.mixins import ActionsMixin, TableMixin
|
||||||
|
|
||||||
from rq.exceptions import NoSuchJobError
|
from rq.exceptions import NoSuchJobError
|
||||||
from rq.job import Job as RQ_Job
|
from rq.job import Job as RQ_Job
|
||||||
from rq.registry import (
|
from rq.registry import (
|
||||||
@ -25,6 +27,7 @@ from rq.registry import (
|
|||||||
)
|
)
|
||||||
from rq.worker import Worker
|
from rq.worker import Worker
|
||||||
from rq.worker_registration import clean_worker_registry
|
from rq.worker_registration import clean_worker_registry
|
||||||
|
from utilities.htmx import is_embedded, is_htmx
|
||||||
from utilities.utils import count_related
|
from utilities.utils import count_related
|
||||||
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
@ -256,6 +259,12 @@ class ConfigRevisionRestoreView(ContentTypePermissionRequiredMixin, View):
|
|||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTaskListView(UserPassesTestMixin, TableMixin, View):
|
||||||
|
|
||||||
|
def test_func(self):
|
||||||
|
return self.request.user.is_staff
|
||||||
|
|
||||||
|
|
||||||
class BackgroundQueueListView(UserPassesTestMixin, View):
|
class BackgroundQueueListView(UserPassesTestMixin, View):
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
@ -269,15 +278,12 @@ class BackgroundQueueListView(UserPassesTestMixin, View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class BackgroundTaskListView(UserPassesTestMixin, View):
|
class BackgroundTaskListView(BaseTaskListView):
|
||||||
|
table = tables.BackgroundTaskTable
|
||||||
|
|
||||||
def test_func(self):
|
def get_table_data(self, request, queue, status):
|
||||||
return self.request.user.is_staff
|
|
||||||
|
|
||||||
def get(self, request, queue_index, status):
|
|
||||||
registry = None
|
registry = None
|
||||||
jobs = []
|
jobs = []
|
||||||
queue = get_queue_by_index(queue_index)
|
|
||||||
|
|
||||||
if status == 'queued':
|
if status == 'queued':
|
||||||
if queue.count > 0:
|
if queue.count > 0:
|
||||||
@ -311,8 +317,27 @@ class BackgroundTaskListView(UserPassesTestMixin, View):
|
|||||||
for job in jobs:
|
for job in jobs:
|
||||||
job.scheduled_at = registry.get_scheduled_time(job)
|
job.scheduled_at = registry.get_scheduled_time(job)
|
||||||
|
|
||||||
table = tables.BackgroundTaskTable(data=jobs, user=request.user, queue_index=queue_index)
|
return jobs
|
||||||
table.configure(request)
|
|
||||||
|
def get(self, request, queue_index, status):
|
||||||
|
queue = get_queue_by_index(queue_index)
|
||||||
|
data = self.get_table_data(request, queue, status)
|
||||||
|
|
||||||
|
table = self.get_table(data, request, False)
|
||||||
|
|
||||||
|
# If this is an HTMX request, return only the rendered table HTML
|
||||||
|
if is_htmx(request):
|
||||||
|
if is_embedded(request):
|
||||||
|
table.embedded = True
|
||||||
|
# Hide selection checkboxes
|
||||||
|
if 'pk' in table.base_columns:
|
||||||
|
table.columns.hide('pk')
|
||||||
|
return render(request, 'htmx/table.html', {
|
||||||
|
'table': table,
|
||||||
|
'queue': queue,
|
||||||
|
'status': status,
|
||||||
|
})
|
||||||
|
|
||||||
return render(request, 'core/background_task_list.html', {
|
return render(request, 'core/background_task_list.html', {
|
||||||
'table': table,
|
'table': table,
|
||||||
'queue': queue,
|
'queue': queue,
|
||||||
@ -320,19 +345,36 @@ class BackgroundTaskListView(UserPassesTestMixin, View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class WorkerListView(UserPassesTestMixin, View):
|
class WorkerListView(BaseTaskListView):
|
||||||
|
table = tables.WorkerTable
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
return self.request.user.is_staff
|
return self.request.user.is_staff
|
||||||
|
|
||||||
def get(self, request, queue_index):
|
def get_table_data(self, request, queue):
|
||||||
queue = get_queue_by_index(queue_index)
|
|
||||||
clean_worker_registry(queue)
|
clean_worker_registry(queue)
|
||||||
all_workers = Worker.all(queue.connection)
|
all_workers = Worker.all(queue.connection)
|
||||||
workers = [worker for worker in all_workers if queue.name in worker.queue_names()]
|
workers = [worker for worker in all_workers if queue.name in worker.queue_names()]
|
||||||
|
return workers
|
||||||
|
|
||||||
|
def get(self, request, queue_index):
|
||||||
|
queue = get_queue_by_index(queue_index)
|
||||||
|
data = self.get_table_data(request, queue)
|
||||||
|
|
||||||
|
table = self.get_table(data, request, False)
|
||||||
|
|
||||||
|
# If this is an HTMX request, return only the rendered table HTML
|
||||||
|
if is_htmx(request):
|
||||||
|
if is_embedded(request):
|
||||||
|
table.embedded = True
|
||||||
|
# Hide selection checkboxes
|
||||||
|
if 'pk' in table.base_columns:
|
||||||
|
table.columns.hide('pk')
|
||||||
|
return render(request, 'htmx/table.html', {
|
||||||
|
'table': table,
|
||||||
|
'queue': queue,
|
||||||
|
})
|
||||||
|
|
||||||
table = tables.WorkerTable(data=workers, user=request.user)
|
|
||||||
table.configure(request)
|
|
||||||
return render(request, 'core/worker_list.html', {
|
return render(request, 'core/worker_list.html', {
|
||||||
'table': table,
|
'table': table,
|
||||||
'queue': queue,
|
'queue': queue,
|
||||||
@ -361,11 +403,18 @@ class BackgroundTaskDetailView(UserPassesTestMixin, View):
|
|||||||
except Exception:
|
except Exception:
|
||||||
data_is_valid = False
|
data_is_valid = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
exc_info = job._exc_info
|
||||||
|
except AttributeError:
|
||||||
|
exc_info = None
|
||||||
|
|
||||||
return render(request, 'core/background_task.html', {
|
return render(request, 'core/background_task.html', {
|
||||||
'queue': queue,
|
'queue': queue,
|
||||||
'job': job,
|
'job': job,
|
||||||
'queue_index': queue_index,
|
'queue_index': queue_index,
|
||||||
'data_is_valid': data_is_valid,
|
'data_is_valid': data_is_valid,
|
||||||
|
'dependency_id': job._dependency_id,
|
||||||
|
'exc_info': exc_info,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
<li class="breadcrumb-item"><a href="{% url 'core:background_queue_list' %}">{% trans 'Background Tasks' %}</a></li>
|
<li class="breadcrumb-item"><a href="{% url 'core:background_queue_list' %}">{% trans 'Background Tasks' %}</a></li>
|
||||||
<li class="breadcrumb-item"><a href="{% url 'core:background_task_list' queue_index=queue_index %}">{{ queue.name }}</a></li>
|
<li class="breadcrumb-item"><a href="{% url 'core:background_task_list' queue_index=queue_index status=job.get_status %}">{{ queue.name }}</a></li>
|
||||||
{% endblock breadcrumbs %}
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block title %}{% trans "Job" %} {{ job.id }}{% endblock %}
|
{% block title %}{% trans "Job" %} {{ job.id }}{% endblock %}
|
||||||
@ -75,6 +75,13 @@
|
|||||||
<th scope="row">{% trans "Kwargs" %}</th>
|
<th scope="row">{% trans "Kwargs" %}</th>
|
||||||
<td>{{ job.kwargs|placeholder }}</td>
|
<td>{{ job.kwargs|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if exc_info %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Exception:" %}</th>
|
||||||
|
<td><pre>{% if job.exc_info %}{{ job.exc_info|linebreaks }}{% endif %}</pre></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{% extends 'generic/_base.html' %}
|
{% extends 'generic/_base.html' %}
|
||||||
|
{% load buttons %}
|
||||||
{% load helpers %}
|
{% load helpers %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
@ -26,6 +27,7 @@
|
|||||||
{% endblock tabs %}
|
{% endblock tabs %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% comment %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-auto ms-auto d-print-none">
|
<div class="col-auto ms-auto d-print-none">
|
||||||
{# Table configuration button #}
|
{# Table configuration button #}
|
||||||
@ -37,9 +39,81 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{# Objects table #}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{% render_table table %}
|
<div class="htmx-container table-responsive" id="object_list">
|
||||||
|
{% include 'htmx/table.html' %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{# /Objects table #}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{# Object list tab #}
|
||||||
|
<div class="tab-pane show active" id="object-list" role="tabpanel" aria-labelledby="object-list-tab">
|
||||||
|
|
||||||
|
{# Object table controls #}
|
||||||
|
{% include 'inc/table_controls_htmx.html' with table_modal="ObjectTable_config" %}
|
||||||
|
|
||||||
|
<form method="post" class="form form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
{# "Select all" form #}
|
||||||
|
{% if table.paginator.num_pages > 1 %}
|
||||||
|
<div id="select-all-box" class="d-none card d-print-none">
|
||||||
|
<div class="form col-md-12">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="float-end">
|
||||||
|
{% if 'bulk_edit' in actions %}
|
||||||
|
{% bulk_edit_button model query_params=request.GET %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'bulk_delete' in actions %}
|
||||||
|
{% bulk_delete_button model query_params=request.GET %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" id="select-all" name="_all" class="form-check-input" />
|
||||||
|
<label for="select-all" class="form-check-label">
|
||||||
|
{% blocktrans trimmed with count=table.rows|length object_type_plural=table.data.verbose_name_plural %}
|
||||||
|
Select <strong>all {{ count }} {{ object_type_plural }}</strong> matching query
|
||||||
|
{% endblocktrans %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="form form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="return_url" value="{% if return_url %}{{ return_url }}{% else %}{{ request.path }}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}{% endif %}" />
|
||||||
|
|
||||||
|
{# Objects table #}
|
||||||
|
<div class="card">
|
||||||
|
<div class="htmx-container table-responsive" id="object_list">
|
||||||
|
{% include 'htmx/table.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{# /Objects table #}
|
||||||
|
|
||||||
|
{# Form buttons #}
|
||||||
|
<div class="btn-list d-print-none mt-2">
|
||||||
|
{% block bulk_buttons %}
|
||||||
|
{% if 'bulk_edit' in actions %}
|
||||||
|
{% bulk_edit_button model query_params=request.GET %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'bulk_delete' in actions %}
|
||||||
|
{% bulk_delete_button model query_params=request.GET %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
{# /Form buttons #}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{# /Object list tab #}
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block modals %}
|
{% block modals %}
|
||||||
|
47
netbox/templates/core/worker_list.html
Normal file
47
netbox/templates/core/worker_list.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{% extends 'generic/_base.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
|
||||||
|
{% block page-header %}
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
{# Breadcrumbs #}
|
||||||
|
<nav class="breadcrumb-container px-3" aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'core:background_queue_list' %}">{% trans 'Background Tasks' %}</a></li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{{ block.super }}
|
||||||
|
{% endblock page-header %}
|
||||||
|
|
||||||
|
{% block title %}{{ status|capfirst }} {% trans "Workers in " %}{{ queue.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block tabs %}
|
||||||
|
<ul class="nav nav-tabs px-3">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a class="nav-link active" role="tab">{% trans "Workers" %}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock tabs %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-auto ms-auto d-print-none">
|
||||||
|
{# Table configuration button #}
|
||||||
|
<div class="table-configure input-group">
|
||||||
|
<button type="button" data-bs-toggle="modal" title="{% trans "Configure Table" %}" data-bs-target="#ObjectTable_config" class="btn">
|
||||||
|
<i class="mdi mdi-cog"></i> {% trans "Configure Table" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
{% render_table table %}
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
{% block modals %}
|
||||||
|
{% table_config_form table table_name="ObjectTable" %}
|
||||||
|
{% endblock modals %}
|
Loading…
Reference in New Issue
Block a user