mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Hide table checkboxes when no bulk actions are enabled
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from copy import deepcopy
|
||||
|
||||
from django.contrib import messages
|
||||
@ -42,27 +43,34 @@ class ObjectListView(BaseMultiObjectView):
|
||||
Attributes:
|
||||
filterset: A django-filter FilterSet that is applied to the queryset
|
||||
filterset_form: The form class used to render filter options
|
||||
actions: Supported actions for the model. Default options are add, import, export, bulk_edit, and bulk_delete
|
||||
actions: Supported actions for the model. When adding custom actions, bulk action names must
|
||||
be prefixed with `bulk_`. Default actions: add, import, export, bulk_edit, bulk_delete
|
||||
action_perms: A dictionary mapping supported actions to a set of permissions required for each
|
||||
"""
|
||||
template_name = 'generic/object_list.html'
|
||||
filterset = None
|
||||
filterset_form = None
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete')
|
||||
action_perms = defaultdict(set, **{
|
||||
'add': {'add'},
|
||||
'import': {'add'},
|
||||
'bulk_edit': {'change'},
|
||||
'bulk_delete': {'delete'},
|
||||
})
|
||||
|
||||
def get_required_permission(self):
|
||||
return get_permission_for_model(self.queryset.model, 'view')
|
||||
|
||||
def get_table(self, request, permissions):
|
||||
def get_table(self, request, bulk_actions=True):
|
||||
"""
|
||||
Return the django-tables2 Table instance to be used for rendering the objects list.
|
||||
|
||||
Args:
|
||||
request: The current request
|
||||
permissions: A dictionary mapping of the view, add, change, and delete permissions to booleans indicating
|
||||
whether the user has each
|
||||
bulk_actions: Show checkboxes for object selection
|
||||
"""
|
||||
table = self.table(self.queryset, user=request.user)
|
||||
if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']):
|
||||
if 'pk' in table.base_columns and bulk_actions:
|
||||
table.columns.show('pk')
|
||||
|
||||
return table
|
||||
@ -135,17 +143,20 @@ class ObjectListView(BaseMultiObjectView):
|
||||
if self.filterset:
|
||||
self.queryset = self.filterset(request.GET, self.queryset).qs
|
||||
|
||||
# Compile a dictionary indicating which permissions are available to the current user for this model
|
||||
permissions = {}
|
||||
for action in ('add', 'change', 'delete', 'view'):
|
||||
perm_name = get_permission_for_model(model, action)
|
||||
permissions[action] = request.user.has_perm(perm_name)
|
||||
# Determine the available actions
|
||||
actions = []
|
||||
for action in self.actions:
|
||||
if request.user.has_perms([
|
||||
get_permission_for_model(model, name) for name in self.action_perms[action]
|
||||
]):
|
||||
actions.append(action)
|
||||
has_bulk_actions = any([a.startswith('bulk_') for a in actions])
|
||||
|
||||
if 'export' in request.GET:
|
||||
|
||||
# Export the current table view
|
||||
if request.GET['export'] == 'table':
|
||||
table = self.get_table(request, permissions)
|
||||
table = self.get_table(request, has_bulk_actions)
|
||||
columns = [name for name, _ in table.selected_columns]
|
||||
return self.export_table(table, columns)
|
||||
|
||||
@ -163,11 +174,11 @@ class ObjectListView(BaseMultiObjectView):
|
||||
|
||||
# Fall back to default table/YAML export
|
||||
else:
|
||||
table = self.get_table(request, permissions)
|
||||
table = self.get_table(request, has_bulk_actions)
|
||||
return self.export_table(table)
|
||||
|
||||
# Render the objects table
|
||||
table = self.get_table(request, permissions)
|
||||
table = self.get_table(request, has_bulk_actions)
|
||||
table.configure(request)
|
||||
|
||||
# If this is an HTMX request, return only the rendered table HTML
|
||||
@ -179,8 +190,7 @@ class ObjectListView(BaseMultiObjectView):
|
||||
context = {
|
||||
'model': model,
|
||||
'table': table,
|
||||
'permissions': permissions,
|
||||
'actions': self.actions,
|
||||
'actions': actions,
|
||||
'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None,
|
||||
**self.get_extra_context(request),
|
||||
}
|
||||
|
@ -73,4 +73,5 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
@ -13,9 +13,6 @@ Blocks:
|
||||
Context:
|
||||
model: The model class being listed
|
||||
table: The table class used for rendering the list of objects
|
||||
permissions: A mapping of add/change/delete permissions to boolean indicating
|
||||
whether the current user possesses each of them. Controls the display of
|
||||
add/edit/delete buttons.
|
||||
actions: A list of buttons to display. This template checks for add, import,
|
||||
export, bulk_edit, and bulk_delete.
|
||||
filter_form: The bound filterset form for filtering the objects list (optional)
|
||||
@ -28,10 +25,10 @@ Context:
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
{% block extra_controls %}{% endblock %}
|
||||
{% if permissions.add and 'add' in actions %}
|
||||
{% if 'add' in actions %}
|
||||
{% add_button model|validated_viewname:"add" %}
|
||||
{% endif %}
|
||||
{% if permissions.add and 'import' in actions %}
|
||||
{% if 'import' in actions %}
|
||||
{% import_button model|validated_viewname:"import" %}
|
||||
{% endif %}
|
||||
{% if 'export' in actions %}
|
||||
@ -72,33 +69,31 @@ Context:
|
||||
|
||||
{# "Select all" form #}
|
||||
{% if table.paginator.num_pages > 1 %}
|
||||
{% with bulk_edit_url=model|validated_viewname:"bulk_edit" bulk_delete_url=model|validated_viewname:"bulk_delete" %}
|
||||
<div id="select-all-box" class="d-none card noprint">
|
||||
<form method="post" class="form col-md-12">
|
||||
{% csrf_token %}
|
||||
<div class="card-body">
|
||||
<div class="float-end">
|
||||
{% if bulk_edit_url and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm" disabled>
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit All
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if bulk_delete_url and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm" disabled>
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete All
|
||||
</button>
|
||||
{% 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">
|
||||
Select <strong>all {{ table.rows|length }} {{ table.data.verbose_name_plural }}</strong> matching query
|
||||
</label>
|
||||
</div>
|
||||
<div id="select-all-box" class="d-none card noprint">
|
||||
<form method="post" class="form col-md-12">
|
||||
{% csrf_token %}
|
||||
<div class="card-body">
|
||||
<div class="float-end">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url model|viewname:"bulk_edit" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm" disabled>
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit All
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url model|viewname:"bulk_delete" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm" disabled>
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete All
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endwith %}
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="select-all" name="_all" class="form-check-input" />
|
||||
<label for="select-all" class="form-check-label">
|
||||
Select <strong>all {{ table.rows|length }} {{ table.data.verbose_name_plural }}</strong> matching query
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Object table controls #}
|
||||
@ -118,17 +113,18 @@ Context:
|
||||
{# Form buttons #}
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% block bulk_buttons %}{% endblock %}
|
||||
{% if 'bulk_edit' in actions and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url model|viewname:"bulk_edit" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url model|viewname:"bulk_delete" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% block bulk_buttons %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url model|viewname:"bulk_edit" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url model|viewname:"bulk_delete" %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -17,4 +17,5 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
@ -9,9 +9,6 @@ def get_permission_for_model(model, action):
|
||||
:param model: A model or instance
|
||||
:param action: View, add, change, or delete (string)
|
||||
"""
|
||||
if action not in ('view', 'add', 'change', 'delete'):
|
||||
raise ValueError(f"Unsupported action: {action}")
|
||||
|
||||
return '{}.{}_{}'.format(
|
||||
model._meta.app_label,
|
||||
action,
|
||||
|
Reference in New Issue
Block a user