1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Create form for setting table preferences

This commit is contained in:
Jeremy Stretch
2020-04-28 12:14:51 -04:00
parent 0ee1112d9d
commit e8d493578b
5 changed files with 92 additions and 18 deletions

View File

@ -0,0 +1,23 @@
{% load form_helpers %}
<button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#tableconfig" title="Configure table"><i class="fa fa-cog"></i></button>
<div class="modal fade" tabindex="-1" id="tableconfig">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Table Configuration</h4>
</div>
<div class="modal-body">
<form action="?return_url={{ request.path }}" method="post" class="form-horizontal">
{% csrf_token %}
{% render_form table_config_form %}
<div class="text-right">
<input type="submit" class="btn btn-primary" name="set" value="Save" />
<input type="submit" class="btn btn-danger" name="clear" value="Clear" />
</div>
</form>
</div>
</div>
</div>
</div>

View File

@ -18,6 +18,9 @@
<h1>{% block title %}{{ content_type.model_class|meta:"verbose_name_plural"|bettertitle }}{% endblock %}</h1>
<div class="row">
<div class="col-md-{% if filter_form %}9{% else %}12{% endif %}">
{% if table_config_form %}
{% include 'inc/table_config_form.html' %}
{% endif %}
{% with bulk_edit_url=content_type.model_class|url_name:"bulk_edit" bulk_delete_url=content_type.model_class|url_name:"bulk_delete" %}
{% if permissions.change or permissions.delete %}
<form method="post" class="form form-horizontal">

View File

@ -137,6 +137,27 @@ def form_from_model(model, fields):
return type('FormFromModel', (forms.Form,), form_fields)
def apply_bootstrap_classes(form):
"""
Apply Bootstrap CSS classes to form elements.
"""
exempt_widgets = [
forms.CheckboxInput,
forms.ClearableFileInput,
forms.FileInput,
forms.RadioSelect
]
for field_name, field in form.fields.items():
if field.widget.__class__ not in exempt_widgets:
css = field.widget.attrs.get('class', '')
field.widget.attrs['class'] = ' '.join([css, 'form-control']).strip()
if field.required and not isinstance(field.widget, forms.FileInput):
field.widget.attrs['required'] = 'required'
if 'placeholder' not in field.widget.attrs:
field.widget.attrs['placeholder'] = field.label
#
# Widgets
#
@ -663,19 +684,7 @@ class BootstrapMixin(forms.BaseForm):
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
exempt_widgets = [
forms.CheckboxInput, forms.ClearableFileInput, forms.FileInput, forms.RadioSelect
]
for field_name, field in self.fields.items():
if field.widget.__class__ not in exempt_widgets:
css = field.widget.attrs.get('class', '')
field.widget.attrs['class'] = ' '.join([css, 'form-control']).strip()
if field.required and not isinstance(field.widget, forms.FileInput):
field.widget.attrs['required'] = 'required'
if 'placeholder' not in field.widget.attrs:
field.widget.attrs['placeholder'] = field.label
apply_bootstrap_classes(self)
class ReturnURLForm(forms.Form):
@ -752,3 +761,23 @@ class ImportForm(BootstrapMixin, forms.Form):
raise forms.ValidationError({
'data': "Invalid YAML data: {}".format(err)
})
class TableConfigForm(forms.Form):
"""
Form for configuring user's table preferences.
"""
def __init__(self, table, *args, **kwargs):
super().__init__(*args, **kwargs)
field_name = f"tables.{table.__class__.__name__}.columns"
self.fields[field_name] = forms.MultipleChoiceField(
choices=table.configurable_columns,
initial=table.visible_columns,
label='Columns',
widget=forms.SelectMultiple(
attrs={'size': 10}
)
)
apply_bootstrap_classes(self)

View File

@ -6,6 +6,11 @@ class BaseTable(tables.Table):
"""
Default table for object lists
"""
class Meta:
attrs = {
'class': 'table table-hover table-headings',
}
def __init__(self, *args, columns=None, **kwargs):
super().__init__(*args, **kwargs)
@ -29,10 +34,19 @@ class BaseTable(tables.Table):
self.base_columns['pk'] = pk
self.sequence.insert(0, 'pk')
class Meta:
attrs = {
'class': 'table table-hover table-headings',
}
@property
def configurable_columns(self):
selected_columns = [
(name, self.columns[name].verbose_name) for name in self.sequence if name != 'pk'
]
available_columns = [
(name, column.verbose_name) for name, column in self.columns.items() if name not in self.sequence and name != 'pk'
]
return selected_columns + available_columns
@property
def visible_columns(self):
return [name for name in self.sequence if self.columns[name].visible]
class ToggleColumn(tables.CheckBoxColumn):

View File

@ -24,7 +24,7 @@ from django_tables2 import RequestConfig
from extras.models import CustomField, CustomFieldValue, ExportTemplate
from extras.querysets import CustomFieldQueryset
from utilities.exceptions import AbortTransaction
from utilities.forms import BootstrapMixin, CSVDataField
from utilities.forms import BootstrapMixin, CSVDataField, TableConfigForm
from utilities.utils import csv_format, prepare_cloned_fields
from .error_handlers import handle_protectederror
from .forms import ConfirmationForm, ImportForm
@ -176,11 +176,16 @@ class ObjectListView(View):
}
RequestConfig(request, paginate).configure(table)
table_config_form = TableConfigForm(
table=table
)
context = {
'content_type': content_type,
'table': table,
'permissions': permissions,
'action_buttons': self.action_buttons,
'table_config_form': table_config_form,
'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None,
}
context.update(self.extra_context())