mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
10587 script pagination (#15343)
* 10587 temp commit * 10587 temp commit * 10587 fix migrations * 10587 pagination * 10587 pagination * 10587 pagination * 10587 review changes
This commit is contained in:
@ -25,7 +25,4 @@ class Migration(migrations.Migration):
|
|||||||
migrations.DeleteModel(
|
migrations.DeleteModel(
|
||||||
name='Report',
|
name='Report',
|
||||||
),
|
),
|
||||||
migrations.DeleteModel(
|
|
||||||
name='ReportModule',
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -82,10 +82,12 @@ def update_scripts(apps, schema_editor):
|
|||||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||||
Script = apps.get_model('extras', 'Script')
|
Script = apps.get_model('extras', 'Script')
|
||||||
ScriptModule = apps.get_model('extras', 'ScriptModule')
|
ScriptModule = apps.get_model('extras', 'ScriptModule')
|
||||||
|
ReportModule = apps.get_model('extras', 'ReportModule')
|
||||||
Job = apps.get_model('core', 'Job')
|
Job = apps.get_model('core', 'Job')
|
||||||
|
|
||||||
script_ct = ContentType.objects.get_for_model(Script)
|
script_ct = ContentType.objects.get_for_model(Script, for_concrete_model=False)
|
||||||
scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule)
|
scriptmodule_ct = ContentType.objects.get_for_model(ScriptModule, for_concrete_model=False)
|
||||||
|
reportmodule_ct = ContentType.objects.get_for_model(ReportModule, for_concrete_model=False)
|
||||||
|
|
||||||
for module in ScriptModule.objects.all():
|
for module in ScriptModule.objects.all():
|
||||||
for script_name in get_module_scripts(module):
|
for script_name in get_module_scripts(module):
|
||||||
@ -96,10 +98,16 @@ def update_scripts(apps, schema_editor):
|
|||||||
|
|
||||||
# Update all Jobs associated with this ScriptModule & script name to point to the new Script object
|
# Update all Jobs associated with this ScriptModule & script name to point to the new Script object
|
||||||
Job.objects.filter(
|
Job.objects.filter(
|
||||||
object_type=scriptmodule_ct,
|
object_type_id=scriptmodule_ct.id,
|
||||||
object_id=module.pk,
|
object_id=module.pk,
|
||||||
name=script_name
|
name=script_name
|
||||||
).update(object_type=script_ct, object_id=script.pk)
|
).update(object_type_id=script_ct.id, object_id=script.pk)
|
||||||
|
# Update all Jobs associated with this ScriptModule & script name to point to the new Script object
|
||||||
|
Job.objects.filter(
|
||||||
|
object_type_id=reportmodule_ct.id,
|
||||||
|
object_id=module.pk,
|
||||||
|
name=script_name
|
||||||
|
).update(object_type_id=script_ct.id, object_id=script.pk)
|
||||||
|
|
||||||
|
|
||||||
def update_event_rules(apps, schema_editor):
|
def update_event_rules(apps, schema_editor):
|
||||||
|
@ -12,4 +12,7 @@ class Migration(migrations.Migration):
|
|||||||
model_name='eventrule',
|
model_name='eventrule',
|
||||||
name='action_parameters',
|
name='action_parameters',
|
||||||
),
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='ReportModule',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -5,7 +5,7 @@ from django.conf import settings
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from extras.models import *
|
from extras.models import *
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import BaseTable, NetBoxTable, columns
|
||||||
from .template_code import *
|
from .template_code import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -21,6 +21,8 @@ __all__ = (
|
|||||||
'JournalEntryTable',
|
'JournalEntryTable',
|
||||||
'ObjectChangeTable',
|
'ObjectChangeTable',
|
||||||
'SavedFilterTable',
|
'SavedFilterTable',
|
||||||
|
'ReportResultsTable',
|
||||||
|
'ScriptResultsTable',
|
||||||
'TaggedItemTable',
|
'TaggedItemTable',
|
||||||
'TagTable',
|
'TagTable',
|
||||||
'WebhookTable',
|
'WebhookTable',
|
||||||
@ -507,3 +509,61 @@ class JournalEntryTable(NetBoxTable):
|
|||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'created', 'created_by', 'assigned_object_type', 'assigned_object', 'kind', 'comments'
|
'pk', 'created', 'created_by', 'assigned_object_type', 'assigned_object', 'kind', 'comments'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptResultsTable(BaseTable):
|
||||||
|
index = tables.Column(
|
||||||
|
verbose_name=_('Line')
|
||||||
|
)
|
||||||
|
time = tables.Column(
|
||||||
|
verbose_name=_('Time')
|
||||||
|
)
|
||||||
|
status = tables.TemplateColumn(
|
||||||
|
template_code="""{% load log_levels %}{% log_level record.status %}""",
|
||||||
|
verbose_name=_('Level')
|
||||||
|
)
|
||||||
|
message = tables.Column(
|
||||||
|
verbose_name=_('Message')
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(BaseTable.Meta):
|
||||||
|
empty_text = _('No results found')
|
||||||
|
fields = (
|
||||||
|
'index', 'time', 'status', 'message',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ReportResultsTable(BaseTable):
|
||||||
|
index = tables.Column(
|
||||||
|
verbose_name=_('Line')
|
||||||
|
)
|
||||||
|
method = tables.Column(
|
||||||
|
verbose_name=_('Method')
|
||||||
|
)
|
||||||
|
time = tables.Column(
|
||||||
|
verbose_name=_('Time')
|
||||||
|
)
|
||||||
|
status = tables.Column(
|
||||||
|
empty_values=(),
|
||||||
|
verbose_name=_('Level')
|
||||||
|
)
|
||||||
|
status = tables.TemplateColumn(
|
||||||
|
template_code="""{% load log_levels %}{% log_level record.status %}""",
|
||||||
|
verbose_name=_('Level')
|
||||||
|
)
|
||||||
|
|
||||||
|
object = tables.Column(
|
||||||
|
verbose_name=_('Object')
|
||||||
|
)
|
||||||
|
url = tables.Column(
|
||||||
|
verbose_name=_('URL')
|
||||||
|
)
|
||||||
|
message = tables.Column(
|
||||||
|
verbose_name=_('Message')
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(BaseTable.Meta):
|
||||||
|
empty_text = _('No results found')
|
||||||
|
fields = (
|
||||||
|
'index', 'method', 'time', 'status', 'object', 'url', 'message',
|
||||||
|
)
|
||||||
|
@ -17,6 +17,7 @@ from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm
|
|||||||
from extras.dashboard.utils import get_widget_class
|
from extras.dashboard.utils import get_widget_class
|
||||||
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
|
from netbox.views.generic.mixins import TableMixin
|
||||||
from utilities.forms import ConfirmationForm, get_field_value
|
from utilities.forms import ConfirmationForm, get_field_value
|
||||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||||
from utilities.rqworker import get_workers_for_queue
|
from utilities.rqworker import get_workers_for_queue
|
||||||
@ -26,6 +27,7 @@ from utilities.views import ContentTypePermissionRequiredMixin, register_model_v
|
|||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
from .scripts import run_script
|
from .scripts import run_script
|
||||||
|
from .tables import ReportResultsTable, ScriptResultsTable
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1143,19 +1145,72 @@ class LegacyScriptRedirectView(ContentTypePermissionRequiredMixin, View):
|
|||||||
return redirect(f'{url}{path}')
|
return redirect(f'{url}{path}')
|
||||||
|
|
||||||
|
|
||||||
class ScriptResultView(generic.ObjectView):
|
class ScriptResultView(TableMixin, generic.ObjectView):
|
||||||
queryset = Job.objects.all()
|
queryset = Job.objects.all()
|
||||||
|
|
||||||
def get_required_permission(self):
|
def get_required_permission(self):
|
||||||
return 'extras.view_script'
|
return 'extras.view_script'
|
||||||
|
|
||||||
|
def get_table(self, job, request, bulk_actions=True):
|
||||||
|
data = []
|
||||||
|
tests = None
|
||||||
|
table = None
|
||||||
|
index = 0
|
||||||
|
if job.data:
|
||||||
|
if 'log' in job.data:
|
||||||
|
if 'tests' in job.data:
|
||||||
|
tests = job.data['tests']
|
||||||
|
|
||||||
|
for log in job.data['log']:
|
||||||
|
index += 1
|
||||||
|
result = {
|
||||||
|
'index': index,
|
||||||
|
'time': log.get('time'),
|
||||||
|
'status': log.get('status'),
|
||||||
|
'message': log.get('message'),
|
||||||
|
}
|
||||||
|
data.append(result)
|
||||||
|
|
||||||
|
table = ScriptResultsTable(data, user=request.user)
|
||||||
|
table.configure(request)
|
||||||
|
else:
|
||||||
|
# for legacy reports
|
||||||
|
tests = job.data
|
||||||
|
|
||||||
|
if tests:
|
||||||
|
for method, test_data in tests.items():
|
||||||
|
if 'log' in test_data:
|
||||||
|
for time, status, obj, url, message in test_data['log']:
|
||||||
|
index += 1
|
||||||
|
result = {
|
||||||
|
'index': index,
|
||||||
|
'method': method,
|
||||||
|
'time': time,
|
||||||
|
'status': status,
|
||||||
|
'object': obj,
|
||||||
|
'url': url,
|
||||||
|
'message': message,
|
||||||
|
}
|
||||||
|
data.append(result)
|
||||||
|
|
||||||
|
table = ReportResultsTable(data, user=request.user)
|
||||||
|
table.configure(request)
|
||||||
|
|
||||||
|
return table
|
||||||
|
|
||||||
def get(self, request, **kwargs):
|
def get(self, request, **kwargs):
|
||||||
|
table = None
|
||||||
job = get_object_or_404(Job.objects.all(), pk=kwargs.get('job_pk'))
|
job = get_object_or_404(Job.objects.all(), pk=kwargs.get('job_pk'))
|
||||||
|
|
||||||
|
if job.completed:
|
||||||
|
table = self.get_table(job, request, bulk_actions=False)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'script': job.object,
|
'script': job.object,
|
||||||
'job': job,
|
'job': job,
|
||||||
|
'table': table,
|
||||||
}
|
}
|
||||||
|
|
||||||
if job.data and 'log' in job.data:
|
if job.data and 'log' in job.data:
|
||||||
# Script
|
# Script
|
||||||
context['tests'] = job.data.get('tests', {})
|
context['tests'] = job.data.get('tests', {})
|
||||||
|
@ -3,124 +3,63 @@
|
|||||||
{% load log_levels %}
|
{% load log_levels %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<p>
|
<div class="htmx-container">
|
||||||
{% if job.started %}
|
<p>
|
||||||
{% trans "Started" %}: <strong>{{ job.started|annotated_date }}</strong>
|
{% if job.started %}
|
||||||
{% elif job.scheduled %}
|
{% trans "Started" %}: <strong>{{ job.started|annotated_date }}</strong>
|
||||||
{% trans "Scheduled for" %}: <strong>{{ job.scheduled|annotated_date }}</strong> ({{ job.scheduled|naturaltime }})
|
{% elif job.scheduled %}
|
||||||
{% else %}
|
{% trans "Scheduled for" %}: <strong>{{ job.scheduled|annotated_date }}</strong> ({{ job.scheduled|naturaltime }})
|
||||||
{% trans "Created" %}: <strong>{{ job.created|annotated_date }}</strong>
|
{% else %}
|
||||||
{% endif %}
|
{% trans "Created" %}: <strong>{{ job.created|annotated_date }}</strong>
|
||||||
|
{% endif %}
|
||||||
|
{% if job.completed %}
|
||||||
|
{% trans "Duration" %}: <strong>{{ job.duration }}</strong>
|
||||||
|
{% endif %}
|
||||||
|
<span id="pending-result-label">{% badge job.get_status_display job.get_status_color %}</span>
|
||||||
|
</p>
|
||||||
{% if job.completed %}
|
{% if job.completed %}
|
||||||
{% trans "Duration" %}: <strong>{{ job.duration }}</strong>
|
{% if tests %}
|
||||||
{% endif %}
|
{# Summary of test methods #}
|
||||||
<span id="pending-result-label">{% badge job.get_status_display job.get_status_color %}</span>
|
<div class="card">
|
||||||
</p>
|
<h5 class="card-header">{% trans "Test Summary" %}</h5>
|
||||||
{% if job.completed %}
|
<table class="table table-hover">
|
||||||
|
{% for test, data in tests.items %}
|
||||||
{# Script log. Legacy reports will not have this. #}
|
|
||||||
{% if 'log' in job.data %}
|
|
||||||
<div class="card mb-3">
|
|
||||||
<h5 class="card-header">{% trans "Log" %}</h5>
|
|
||||||
{% if job.data.log %}
|
|
||||||
<table class="table table-hover panel-body">
|
|
||||||
<tr>
|
|
||||||
<th>{% trans "Line" %}</th>
|
|
||||||
<th>{% trans "Time" %}</th>
|
|
||||||
<th>{% trans "Level" %}</th>
|
|
||||||
<th>{% trans "Message" %}</th>
|
|
||||||
</tr>
|
|
||||||
{% for log in job.data.log %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ forloop.counter }}</td>
|
<td class="font-monospace"><a href="#{{ test }}">{{ test }}</a></td>
|
||||||
<td>{{ log.time|placeholder }}</td>
|
<td class="text-end report-stats">
|
||||||
<td>{% log_level log.status %}</td>
|
<span class="badge text-bg-success">{{ data.success }}</span>
|
||||||
<td>{{ log.message|markdown }}</td>
|
<span class="badge text-bg-info">{{ data.info }}</span>
|
||||||
|
<span class="badge text-bg-warning">{{ data.warning }}</span>
|
||||||
|
<span class="badge text-bg-danger">{{ data.failure }}</span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
</div>
|
||||||
<div class="card-body text-muted">{% trans "None" %}</div>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# Script output. Legacy reports will not have this. #}
|
{% if table %}
|
||||||
{% if 'output' in job.data %}
|
|
||||||
<div class="card mb-3">
|
|
||||||
<h5 class="card-header">{% trans "Output" %}</h5>
|
|
||||||
{% if job.data.output %}
|
|
||||||
<pre class="card-body font-monospace">{{ job.data.output }}</pre>
|
|
||||||
{% else %}
|
|
||||||
<div class="card-body text-muted">{% trans "None" %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# Test method logs (for legacy Reports) #}
|
|
||||||
{% if tests %}
|
|
||||||
|
|
||||||
{# Summary of test methods #}
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">{% trans "Test Summary" %}</h5>
|
<div class="table-responsive" id="object_list">
|
||||||
<table class="table table-hover">
|
<h5 class="card-header">{% trans "Log" %}</h5>
|
||||||
{% for test, data in tests.items %}
|
{% include 'htmx/table.html' %}
|
||||||
<tr>
|
</div>
|
||||||
<td class="font-monospace"><a href="#{{ test }}">{{ test }}</a></td>
|
|
||||||
<td class="text-end report-stats">
|
|
||||||
<span class="badge text-bg-success">{{ data.success }}</span>
|
|
||||||
<span class="badge text-bg-info">{{ data.info }}</span>
|
|
||||||
<span class="badge text-bg-warning">{{ data.warning }}</span>
|
|
||||||
<span class="badge text-bg-danger">{{ data.failure }}</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{# Detailed results for individual tests #}
|
{# Script output. Legacy reports will not have this. #}
|
||||||
<div class="card">
|
{% if 'output' in job.data %}
|
||||||
<h5 class="card-header">{% trans "Test Details" %}</h5>
|
<div class="card mb-3">
|
||||||
<table class="table table-hover report">
|
<h5 class="card-header">{% trans "Output" %}</h5>
|
||||||
<thead>
|
{% if job.data.output %}
|
||||||
<tr class="table-headings">
|
<pre class="card-body font-monospace">{{ job.data.output }}</pre>
|
||||||
<th>{% trans "Time" %}</th>
|
{% else %}
|
||||||
<th>{% trans "Level" %}</th>
|
<div class="card-body text-muted">{% trans "None" %}</div>
|
||||||
<th>{% trans "Object" %}</th>
|
{% endif %}
|
||||||
<th>{% trans "Message" %}</th>
|
</div>
|
||||||
</tr>
|
{% endif %}
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for test, data in tests.items %}
|
|
||||||
<tr>
|
|
||||||
<th colspan="4" style="font-family: monospace">
|
|
||||||
<a name="{{ test }}"></a>{{ test }}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
{% for time, level, obj, url, message in data.log %}
|
|
||||||
<tr class="{% if level == 'failure' %}danger{% elif level %}{{ level }}{% endif %}">
|
|
||||||
<td>{{ time }}</td>
|
|
||||||
<td>
|
|
||||||
<label class="badge text-bg-{% if level == 'failure' %}danger{% else %}{{ level }}{% endif %}">{{ level|title }}</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if obj and url %}
|
|
||||||
<a href="{{ url }}">{{ obj }}</a>
|
|
||||||
{% elif obj %}
|
|
||||||
{{ obj }}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td class="rendered-markdown">{{ message|markdown }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{% elif job.started %}
|
||||||
|
{% include 'extras/inc/result_pending.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif job.started %}
|
</div>
|
||||||
{% include 'extras/inc/result_pending.html' %}
|
|
||||||
{% endif %}
|
|
||||||
|
@ -32,28 +32,74 @@
|
|||||||
{% block tabs %}
|
{% block tabs %}
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a href="#log" role="tab" data-bs-toggle="tab" class="nav-link active">{% trans "Log" %}</a>
|
<a href="#results" role="tab" data-bs-toggle="tab" class="nav-link active">{% trans "Results" %}</a>
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<a href="#source" role="tab" data-bs-toggle="tab" class="nav-link">{% trans "Source" %}</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div role="tabpanel" class="tab-pane active" id="log">
|
{# Object list tab #}
|
||||||
<div class="row">
|
<div class="tab-pane show active" id="results" role="tabpanel" aria-labelledby="results-tab">
|
||||||
<div class="col col-md-12"{% if not job.completed %} hx-get="{% url 'extras:script_result' job_pk=job.pk %}" hx-trigger="load delay:0.5s, every 5s"{% endif %}>
|
|
||||||
{% include 'extras/htmx/script_result.html' %}
|
{# Object table controls #}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-auto ms-auto d-print-none">
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<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>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<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="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="col col-md-12"{% if not job.completed %} hx-get="{% url 'extras:script_result' job_pk=job.pk %}" hx-trigger="load delay:0.5s, every 5s"{% endif %}>
|
||||||
|
{% include 'extras/htmx/script_result.html' %}
|
||||||
|
</div>
|
||||||
|
{# /Objects table #}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{# /Object list tab #}
|
||||||
<div role="tabpanel" class="tab-pane" id="source">
|
|
||||||
<p><code>{{ script.filename }}</code></p>
|
{# Filters tab #}
|
||||||
<pre class="block">{{ script.source }}</pre>
|
{% if filter_form %}
|
||||||
</div>
|
<div class="tab-pane show" id="filters-form" role="tabpanel" aria-labelledby="filters-form-tab">
|
||||||
|
{% include 'inc/filter_list.html' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{# /Filters tab #}
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block modals %}
|
{% block modals %}
|
||||||
{% include 'inc/htmx_modal.html' %}
|
{% table_config_form table table_name="ObjectTable" %}
|
||||||
{% endblock modals %}
|
{% endblock modals %}
|
||||||
|
Reference in New Issue
Block a user