mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Merge pull request #4555 from netbox-community/492-table-column-ordering
Closes #492: Table column ordering
This commit is contained in:
commit
80f08e6830
@ -8,3 +8,4 @@ The `users.UserConfig` model holds individual preferences for each user in the f
|
||||
| ---- | ----------- |
|
||||
| extras.configcontext.format | Preferred format when rendering config context data (JSON or YAML) |
|
||||
| pagination.per_page | The number of items to display per page of a paginated table |
|
||||
| tables.${table_name}.columns | The ordered list of columns to display when viewing the table |
|
||||
|
@ -27,18 +27,15 @@ STATUS_LABEL = """
|
||||
class ProviderTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
circuit_count = tables.Column(
|
||||
accessor=Accessor('count_circuits'),
|
||||
verbose_name='Circuits'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Provider
|
||||
fields = ('pk', 'name', 'asn', 'account',)
|
||||
|
||||
|
||||
class ProviderDetailTable(ProviderTable):
|
||||
circuit_count = tables.Column(accessor=Accessor('count_circuits'), verbose_name='Circuits')
|
||||
|
||||
class Meta(ProviderTable.Meta):
|
||||
model = Provider
|
||||
fields = ('pk', 'name', 'asn', 'account', 'circuit_count')
|
||||
fields = ('pk', 'name', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'circuit_count')
|
||||
default_columns = ('pk', 'name', 'asn', 'account', 'circuit_count')
|
||||
|
||||
|
||||
#
|
||||
@ -58,6 +55,7 @@ class CircuitTypeTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = CircuitType
|
||||
fields = ('pk', 'name', 'circuit_count', 'description', 'slug', 'actions')
|
||||
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -79,4 +77,8 @@ class CircuitTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Circuit
|
||||
fields = ('pk', 'cid', 'status', 'type', 'provider', 'tenant', 'a_side', 'z_side', 'description')
|
||||
fields = (
|
||||
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'a_side', 'z_side', 'install_date', 'commit_rate',
|
||||
'description',
|
||||
)
|
||||
default_columns = ('pk', 'cid', 'provider', 'type', 'status', 'tenant', 'a_side', 'z_side', 'description')
|
||||
|
@ -28,7 +28,7 @@ class ProviderListView(PermissionRequiredMixin, ObjectListView):
|
||||
queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
|
||||
filterset = filters.ProviderFilterSet
|
||||
filterset_form = forms.ProviderFilterForm
|
||||
table = tables.ProviderDetailTable
|
||||
table = tables.ProviderTable
|
||||
|
||||
|
||||
class ProviderView(PermissionRequiredMixin, View):
|
||||
@ -87,7 +87,7 @@ class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
|
||||
class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
permission_required = 'circuits.change_provider'
|
||||
queryset = Provider.objects.all()
|
||||
queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
|
||||
filterset = filters.ProviderFilterSet
|
||||
table = tables.ProviderTable
|
||||
form = forms.ProviderBulkEditForm
|
||||
@ -96,7 +96,7 @@ class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
|
||||
class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'circuits.delete_provider'
|
||||
queryset = Provider.objects.all()
|
||||
queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
|
||||
filterset = filters.ProviderFilterSet
|
||||
table = tables.ProviderTable
|
||||
default_return_url = 'circuits:provider_list'
|
||||
|
@ -205,9 +205,13 @@ def get_component_template_actions(model_name):
|
||||
|
||||
class RegionTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.TemplateColumn(template_code=MPTT_LINK, orderable=False)
|
||||
site_count = tables.Column(verbose_name='Sites')
|
||||
slug = tables.Column(verbose_name='Slug')
|
||||
name = tables.TemplateColumn(
|
||||
template_code=MPTT_LINK,
|
||||
orderable=False
|
||||
)
|
||||
site_count = tables.Column(
|
||||
verbose_name='Sites'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=REGION_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -216,7 +220,8 @@ class RegionTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Region
|
||||
fields = ('pk', 'name', 'site_count', 'description', 'slug', 'actions')
|
||||
fields = ('pk', 'name', 'slug', 'site_count', 'description', 'actions')
|
||||
default_columns = ('pk', 'name', 'site_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -225,14 +230,27 @@ class RegionTable(BaseTable):
|
||||
|
||||
class SiteTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn(order_by=('_name',))
|
||||
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
|
||||
region = tables.TemplateColumn(template_code=SITE_REGION_LINK)
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
name = tables.LinkColumn(
|
||||
order_by=('_name',)
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
region = tables.TemplateColumn(
|
||||
template_code=SITE_REGION_LINK
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Site
|
||||
fields = ('pk', 'name', 'status', 'facility', 'region', 'tenant', 'asn', 'description')
|
||||
fields = (
|
||||
'pk', 'name', 'slug', 'status', 'facility', 'region', 'tenant', 'asn', 'time_zone', 'description',
|
||||
'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone',
|
||||
'contact_email',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'status', 'facility', 'region', 'tenant', 'asn', 'description')
|
||||
|
||||
|
||||
#
|
||||
@ -253,7 +271,6 @@ class RackGroupTable(BaseTable):
|
||||
rack_count = tables.Column(
|
||||
verbose_name='Racks'
|
||||
)
|
||||
slug = tables.Column()
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=RACKGROUP_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -263,6 +280,7 @@ class RackGroupTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = RackGroup
|
||||
fields = ('pk', 'name', 'site', 'rack_count', 'description', 'slug', 'actions')
|
||||
default_columns = ('pk', 'name', 'site', 'rack_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -282,6 +300,7 @@ class RackRoleTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = RackRole
|
||||
fields = ('pk', 'name', 'rack_count', 'color', 'description', 'slug', 'actions')
|
||||
default_columns = ('pk', 'name', 'rack_count', 'color', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -290,17 +309,34 @@ class RackRoleTable(BaseTable):
|
||||
|
||||
class RackTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn(order_by=('_name',))
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
role = tables.TemplateColumn(RACK_ROLE)
|
||||
u_height = tables.TemplateColumn("{{ record.u_height }}U", verbose_name='Height')
|
||||
name = tables.LinkColumn(
|
||||
order_by=('_name',)
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_code=RACK_ROLE
|
||||
)
|
||||
u_height = tables.TemplateColumn(
|
||||
template_code="{{ record.u_height }}U",
|
||||
verbose_name='Height'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Rack
|
||||
fields = ('pk', 'name', 'site', 'group', 'status', 'facility_id', 'tenant', 'role', 'u_height')
|
||||
fields = (
|
||||
'pk', 'name', 'site', 'group', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', 'type',
|
||||
'width', 'u_height',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'site', 'group', 'status', 'facility_id', 'tenant', 'role', 'u_height')
|
||||
|
||||
|
||||
class RackDetailTable(RackTable):
|
||||
@ -321,6 +357,10 @@ class RackDetailTable(RackTable):
|
||||
|
||||
class Meta(RackTable.Meta):
|
||||
fields = (
|
||||
'pk', 'name', 'site', 'group', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', 'type',
|
||||
'width', 'u_height', 'device_count', 'get_utilization', 'get_power_utilization',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'site', 'group', 'status', 'facility_id', 'tenant', 'role', 'u_height', 'device_count',
|
||||
'get_utilization', 'get_power_utilization',
|
||||
)
|
||||
@ -364,6 +404,9 @@ class RackReservationTable(BaseTable):
|
||||
fields = (
|
||||
'pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'created', 'tenant', 'description', 'actions',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description', 'actions',
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
@ -416,9 +459,12 @@ class DeviceTypeTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = DeviceType
|
||||
fields = (
|
||||
'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||
'pk', 'model', 'manufacturer', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||
'instance_count',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'instance_count',
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
@ -427,7 +473,9 @@ class DeviceTypeTable(BaseTable):
|
||||
|
||||
class ConsolePortTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('consoleporttemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -441,7 +489,10 @@ class ConsolePortTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class ConsolePortImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ConsolePort
|
||||
@ -451,7 +502,9 @@ class ConsolePortImportTable(BaseTable):
|
||||
|
||||
class ConsoleServerPortTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('consoleserverporttemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -465,7 +518,10 @@ class ConsoleServerPortTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class ConsoleServerPortImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ConsoleServerPort
|
||||
@ -475,7 +531,9 @@ class ConsoleServerPortImportTable(BaseTable):
|
||||
|
||||
class PowerPortTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('powerporttemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -489,7 +547,10 @@ class PowerPortTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class PowerPortImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = PowerPort
|
||||
@ -499,7 +560,9 @@ class PowerPortImportTable(BaseTable):
|
||||
|
||||
class PowerOutletTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('poweroutlettemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -513,7 +576,10 @@ class PowerOutletTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class PowerOutletImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = PowerOutlet
|
||||
@ -523,7 +589,9 @@ class PowerOutletImportTable(BaseTable):
|
||||
|
||||
class InterfaceTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
mgmt_only = tables.TemplateColumn("{% if value %}OOB Management{% endif %}")
|
||||
mgmt_only = tables.TemplateColumn(
|
||||
template_code="{% if value %}OOB Management{% endif %}"
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('interfacetemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -537,18 +605,30 @@ class InterfaceTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class InterfaceImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
virtual_machine = tables.LinkColumn('virtualization:virtualmachine', args=[Accessor('virtual_machine.pk')], verbose_name='Virtual Machine')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
virtual_machine = tables.LinkColumn(
|
||||
viewname='virtualization:virtualmachine',
|
||||
args=[Accessor('virtual_machine.pk')],
|
||||
verbose_name='Virtual Machine'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Interface
|
||||
fields = ('device', 'virtual_machine', 'name', 'description', 'lag', 'type', 'enabled', 'mac_address', 'mtu', 'mgmt_only', 'mode')
|
||||
fields = (
|
||||
'device', 'virtual_machine', 'name', 'description', 'lag', 'type', 'enabled', 'mac_address', 'mtu',
|
||||
'mgmt_only', 'mode',
|
||||
)
|
||||
empty_text = False
|
||||
|
||||
|
||||
class FrontPortTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
rear_port_position = tables.Column(
|
||||
verbose_name='Position'
|
||||
)
|
||||
@ -565,7 +645,10 @@ class FrontPortTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class FrontPortImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = FrontPort
|
||||
@ -575,7 +658,9 @@ class FrontPortImportTable(BaseTable):
|
||||
|
||||
class RearPortTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('rearporttemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -589,7 +674,10 @@ class RearPortTemplateTable(BaseTable):
|
||||
|
||||
|
||||
class RearPortImportTable(BaseTable):
|
||||
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = RearPort
|
||||
@ -599,7 +687,9 @@ class RearPortImportTable(BaseTable):
|
||||
|
||||
class DeviceBayTemplateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.Column(order_by=('_name',))
|
||||
name = tables.Column(
|
||||
order_by=('_name',)
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=get_component_template_actions('devicebaytemplate'),
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -630,8 +720,10 @@ class DeviceRoleTable(BaseTable):
|
||||
orderable=False,
|
||||
verbose_name='VMs'
|
||||
)
|
||||
color = tables.TemplateColumn(COLOR_LABEL, verbose_name='Label')
|
||||
slug = tables.Column(verbose_name='Slug')
|
||||
color = tables.TemplateColumn(
|
||||
template_code=COLOR_LABEL,
|
||||
verbose_name='Label'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=DEVICEROLE_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -641,6 +733,7 @@ class DeviceRoleTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = DeviceRole
|
||||
fields = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'actions')
|
||||
default_columns = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -670,7 +763,11 @@ class PlatformTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Platform
|
||||
fields = (
|
||||
'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'description', 'actions',
|
||||
'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args',
|
||||
'description', 'actions',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'napalm_driver', 'description', 'actions',
|
||||
)
|
||||
|
||||
|
||||
@ -684,40 +781,96 @@ class DeviceTable(BaseTable):
|
||||
order_by=('_name',),
|
||||
template_code=DEVICE_LINK
|
||||
)
|
||||
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
|
||||
device_role = tables.TemplateColumn(DEVICE_ROLE, verbose_name='Role')
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
rack = tables.LinkColumn(
|
||||
viewname='dcim:rack',
|
||||
args=[Accessor('rack.pk')]
|
||||
)
|
||||
device_role = tables.TemplateColumn(
|
||||
template_code=DEVICE_ROLE,
|
||||
verbose_name='Role'
|
||||
)
|
||||
device_type = tables.LinkColumn(
|
||||
'dcim:devicetype', args=[Accessor('device_type.pk')], verbose_name='Type',
|
||||
viewname='dcim:devicetype',
|
||||
args=[Accessor('device_type.pk')],
|
||||
verbose_name='Type',
|
||||
text=lambda record: record.device_type.display_name
|
||||
)
|
||||
primary_ip = tables.TemplateColumn(
|
||||
template_code=DEVICE_PRIMARY_IP,
|
||||
orderable=False,
|
||||
verbose_name='IP Address'
|
||||
)
|
||||
primary_ip4 = tables.LinkColumn(
|
||||
viewname='ipam:ipaddress',
|
||||
args=[Accessor('primary_ip4.pk')],
|
||||
verbose_name='IPv4 Address'
|
||||
)
|
||||
primary_ip6 = tables.LinkColumn(
|
||||
viewname='ipam:ipaddress',
|
||||
args=[Accessor('primary_ip6.pk')],
|
||||
verbose_name='IPv6 Address'
|
||||
)
|
||||
cluster = tables.LinkColumn(
|
||||
viewname='virtualization:cluster',
|
||||
args=[Accessor('cluster.pk')]
|
||||
)
|
||||
virtual_chassis = tables.LinkColumn(
|
||||
viewname='dcim:virtualchassis',
|
||||
args=[Accessor('virtual_chassis.pk')]
|
||||
)
|
||||
vc_position = tables.Column(
|
||||
verbose_name='VC Position'
|
||||
)
|
||||
vc_priority = tables.Column(
|
||||
verbose_name='VC Priority'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Device
|
||||
fields = ('pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type')
|
||||
|
||||
|
||||
class DeviceDetailTable(DeviceTable):
|
||||
primary_ip = tables.TemplateColumn(
|
||||
orderable=False, verbose_name='IP Address', template_code=DEVICE_PRIMARY_IP
|
||||
)
|
||||
|
||||
class Meta(DeviceTable.Meta):
|
||||
model = Device
|
||||
fields = ('pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip')
|
||||
fields = (
|
||||
'pk', 'name', 'status', 'tenant', 'device_role', 'device_type', 'platform', 'serial', 'asset_tag', 'site',
|
||||
'rack', 'position', 'face', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis',
|
||||
'vc_position', 'vc_priority',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip',
|
||||
)
|
||||
|
||||
|
||||
class DeviceImportTable(BaseTable):
|
||||
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
|
||||
status = tables.TemplateColumn(template_code=STATUS_LABEL, verbose_name='Status')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
||||
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
|
||||
position = tables.Column(verbose_name='Position')
|
||||
device_role = tables.Column(verbose_name='Role')
|
||||
device_type = tables.Column(verbose_name='Type')
|
||||
name = tables.TemplateColumn(
|
||||
template_code=DEVICE_LINK
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
rack = tables.LinkColumn(
|
||||
viewname='dcim:rack',
|
||||
args=[Accessor('rack.pk')]
|
||||
)
|
||||
device_role = tables.Column(
|
||||
verbose_name='Role'
|
||||
)
|
||||
device_type = tables.Column(
|
||||
verbose_name='Type'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Device
|
||||
@ -893,23 +1046,23 @@ class CableTable(BaseTable):
|
||||
template_code=CABLE_TERMINATION_PARENT,
|
||||
accessor=Accessor('termination_a'),
|
||||
orderable=False,
|
||||
verbose_name='Termination A'
|
||||
verbose_name='Side A'
|
||||
)
|
||||
termination_a = tables.LinkColumn(
|
||||
accessor=Accessor('termination_a'),
|
||||
orderable=False,
|
||||
verbose_name=''
|
||||
verbose_name='Termination A'
|
||||
)
|
||||
termination_b_parent = tables.TemplateColumn(
|
||||
template_code=CABLE_TERMINATION_PARENT,
|
||||
accessor=Accessor('termination_b'),
|
||||
orderable=False,
|
||||
verbose_name='Termination B'
|
||||
verbose_name='Side B'
|
||||
)
|
||||
termination_b = tables.LinkColumn(
|
||||
accessor=Accessor('termination_b'),
|
||||
orderable=False,
|
||||
verbose_name=''
|
||||
verbose_name='Termination B'
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
@ -926,6 +1079,10 @@ class CableTable(BaseTable):
|
||||
'pk', 'id', 'label', 'termination_a_parent', 'termination_a', 'termination_b_parent', 'termination_b',
|
||||
'status', 'type', 'color', 'length',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'id', 'label', 'termination_a_parent', 'termination_a', 'termination_b_parent', 'termination_b',
|
||||
'status', 'type',
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
@ -993,10 +1150,6 @@ class InterfaceConnectionTable(BaseTable):
|
||||
args=[Accessor('pk')],
|
||||
verbose_name='Interface A'
|
||||
)
|
||||
description_a = tables.Column(
|
||||
accessor=Accessor('description'),
|
||||
verbose_name='Description'
|
||||
)
|
||||
device_b = tables.LinkColumn(
|
||||
viewname='dcim:device',
|
||||
accessor=Accessor('_connected_interface.device'),
|
||||
@ -1009,15 +1162,11 @@ class InterfaceConnectionTable(BaseTable):
|
||||
args=[Accessor('_connected_interface.pk')],
|
||||
verbose_name='Interface B'
|
||||
)
|
||||
description_b = tables.Column(
|
||||
accessor=Accessor('_connected_interface.description'),
|
||||
verbose_name='Description'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Interface
|
||||
fields = (
|
||||
'device_a', 'interface_a', 'description_a', 'device_b', 'interface_b', 'description_b', 'connection_status',
|
||||
'device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status',
|
||||
)
|
||||
|
||||
|
||||
@ -1027,12 +1176,21 @@ class InterfaceConnectionTable(BaseTable):
|
||||
|
||||
class InventoryItemTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
device = tables.LinkColumn('dcim:device_inventory', args=[Accessor('device.pk')])
|
||||
manufacturer = tables.Column(accessor=Accessor('manufacturer.name'), verbose_name='Manufacturer')
|
||||
device = tables.LinkColumn(
|
||||
viewname='dcim:device_inventory',
|
||||
args=[Accessor('device.pk')]
|
||||
)
|
||||
manufacturer = tables.Column(
|
||||
accessor=Accessor('manufacturer.name')
|
||||
)
|
||||
discovered = BooleanColumn()
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = InventoryItem
|
||||
fields = ('pk', 'device', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description')
|
||||
fields = (
|
||||
'pk', 'device', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered'
|
||||
)
|
||||
default_columns = ('pk', 'device', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag')
|
||||
|
||||
|
||||
#
|
||||
@ -1052,6 +1210,7 @@ class VirtualChassisTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VirtualChassis
|
||||
fields = ('pk', 'name', 'domain', 'member_count')
|
||||
default_columns = ('pk', 'name', 'domain', 'member_count')
|
||||
|
||||
|
||||
#
|
||||
@ -1073,6 +1232,7 @@ class PowerPanelTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = PowerPanel
|
||||
fields = ('pk', 'name', 'site', 'rack_group', 'powerfeed_count')
|
||||
default_columns = ('pk', 'name', 'site', 'rack_group', 'powerfeed_count')
|
||||
|
||||
|
||||
#
|
||||
@ -1096,7 +1256,19 @@ class PowerFeedTable(BaseTable):
|
||||
type = tables.TemplateColumn(
|
||||
template_code=TYPE_LABEL
|
||||
)
|
||||
max_utilization = tables.TemplateColumn(
|
||||
template_code="{{ value }}%"
|
||||
)
|
||||
available_power = tables.Column(
|
||||
verbose_name='Available power (VA)'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = PowerFeed
|
||||
fields = ('pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase')
|
||||
fields = (
|
||||
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
|
||||
'max_utilization', 'available_power',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
|
||||
)
|
||||
|
@ -1095,7 +1095,7 @@ class DeviceListView(PermissionRequiredMixin, ObjectListView):
|
||||
)
|
||||
filterset = filters.DeviceFilterSet
|
||||
filterset_form = forms.DeviceFilterForm
|
||||
table = tables.DeviceDetailTable
|
||||
table = tables.DeviceTable
|
||||
template_name = 'dcim/device_list.html'
|
||||
|
||||
|
||||
@ -2278,19 +2278,15 @@ class InterfaceConnectionsListView(PermissionRequiredMixin, ObjectListView):
|
||||
csv_data = [
|
||||
# Headers
|
||||
','.join([
|
||||
'device_a', 'interface_a', 'interface_a_description',
|
||||
'device_b', 'interface_b', 'interface_b_description',
|
||||
'connection_status'
|
||||
'device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status'
|
||||
])
|
||||
]
|
||||
for obj in self.queryset:
|
||||
csv = csv_format([
|
||||
obj.connected_endpoint.device.identifier if obj.connected_endpoint else None,
|
||||
obj.connected_endpoint.name if obj.connected_endpoint else None,
|
||||
obj.connected_endpoint.description if obj.connected_endpoint else None,
|
||||
obj.device.identifier,
|
||||
obj.name,
|
||||
obj.description,
|
||||
obj.get_connection_status_display(),
|
||||
])
|
||||
csv_data.append(csv)
|
||||
|
@ -104,7 +104,11 @@ class ConfigContextTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ConfigContext
|
||||
fields = ('pk', 'name', 'weight', 'is_active', 'description')
|
||||
fields = (
|
||||
'pk', 'name', 'weight', 'is_active', 'description', 'regions', 'sites', 'roles', 'platforms',
|
||||
'cluster_groups', 'clusters', 'tenant_groups', 'tenants',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'weight', 'is_active', 'description')
|
||||
|
||||
|
||||
class ObjectChangeTable(BaseTable):
|
||||
|
@ -190,12 +190,20 @@ TENANT_LINK = """
|
||||
class VRFTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
rd = tables.Column(verbose_name='RD')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
rd = tables.Column(
|
||||
verbose_name='RD'
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
enforce_unique = BooleanColumn(
|
||||
verbose_name='Unique'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VRF
|
||||
fields = ('pk', 'name', 'rd', 'tenant', 'description')
|
||||
fields = ('pk', 'name', 'rd', 'tenant', 'enforce_unique', 'description')
|
||||
default_columns = ('pk', 'name', 'rd', 'tenant', 'description')
|
||||
|
||||
|
||||
#
|
||||
@ -204,14 +212,23 @@ class VRFTable(BaseTable):
|
||||
|
||||
class RIRTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn(verbose_name='Name')
|
||||
is_private = BooleanColumn(verbose_name='Private')
|
||||
aggregate_count = tables.Column(verbose_name='Aggregates')
|
||||
actions = tables.TemplateColumn(template_code=RIR_ACTIONS, attrs={'td': {'class': 'text-right noprint'}}, verbose_name='')
|
||||
name = tables.LinkColumn()
|
||||
is_private = BooleanColumn(
|
||||
verbose_name='Private'
|
||||
)
|
||||
aggregate_count = tables.Column(
|
||||
verbose_name='Aggregates'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=RIR_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
verbose_name=''
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = RIR
|
||||
fields = ('pk', 'name', 'is_private', 'aggregate_count', 'description', 'actions')
|
||||
fields = ('pk', 'name', 'slug', 'is_private', 'aggregate_count', 'description', 'actions')
|
||||
default_columns = ('pk', 'name', 'is_private', 'aggregate_count', 'description', 'actions')
|
||||
|
||||
|
||||
class RIRDetailTable(RIRTable):
|
||||
@ -247,6 +264,10 @@ class RIRDetailTable(RIRTable):
|
||||
|
||||
class Meta(RIRTable.Meta):
|
||||
fields = (
|
||||
'pk', 'name', 'slug', 'is_private', 'aggregate_count', 'stats_total', 'stats_active', 'stats_reserved',
|
||||
'stats_deprecated', 'stats_available', 'utilization', 'actions',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'is_private', 'aggregate_count', 'stats_total', 'stats_active', 'stats_reserved',
|
||||
'stats_deprecated', 'stats_available', 'utilization', 'actions',
|
||||
)
|
||||
@ -258,8 +279,13 @@ class RIRDetailTable(RIRTable):
|
||||
|
||||
class AggregateTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
prefix = tables.LinkColumn(verbose_name='Aggregate')
|
||||
date_added = tables.DateColumn(format="Y-m-d", verbose_name='Added')
|
||||
prefix = tables.LinkColumn(
|
||||
verbose_name='Aggregate'
|
||||
)
|
||||
date_added = tables.DateColumn(
|
||||
format="Y-m-d",
|
||||
verbose_name='Added'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Aggregate
|
||||
@ -267,8 +293,13 @@ class AggregateTable(BaseTable):
|
||||
|
||||
|
||||
class AggregateDetailTable(AggregateTable):
|
||||
child_count = tables.Column(verbose_name='Prefixes')
|
||||
utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
|
||||
child_count = tables.Column(
|
||||
verbose_name='Prefixes'
|
||||
)
|
||||
utilization = tables.TemplateColumn(
|
||||
template_code=UTILIZATION_GRAPH,
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta(AggregateTable.Meta):
|
||||
fields = ('pk', 'prefix', 'rir', 'child_count', 'utilization', 'date_added', 'description')
|
||||
@ -300,7 +331,8 @@ class RoleTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Role
|
||||
fields = ('pk', 'name', 'prefix_count', 'vlan_count', 'description', 'slug', 'weight', 'actions')
|
||||
fields = ('pk', 'name', 'slug', 'prefix_count', 'vlan_count', 'description', 'weight', 'actions')
|
||||
default_columns = ('pk', 'name', 'prefix_count', 'vlan_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -309,28 +341,61 @@ class RoleTable(BaseTable):
|
||||
|
||||
class PrefixTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
prefix = tables.TemplateColumn(PREFIX_LINK, attrs={'th': {'style': 'padding-left: 17px'}})
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
|
||||
tenant = tables.TemplateColumn(template_code=TENANT_LINK)
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN')
|
||||
role = tables.TemplateColumn(PREFIX_ROLE_LINK)
|
||||
prefix = tables.TemplateColumn(
|
||||
template_code=PREFIX_LINK,
|
||||
attrs={'th': {'style': 'padding-left: 17px'}}
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
vrf = tables.TemplateColumn(
|
||||
template_code=VRF_LINK,
|
||||
verbose_name='VRF'
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=TENANT_LINK
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
vlan = tables.LinkColumn(
|
||||
viewname='ipam:vlan',
|
||||
args=[Accessor('vlan.pk')],
|
||||
verbose_name='VLAN'
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_code=PREFIX_ROLE_LINK
|
||||
)
|
||||
is_pool = BooleanColumn(
|
||||
verbose_name='Pool'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Prefix
|
||||
fields = ('pk', 'prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'description')
|
||||
fields = ('pk', 'prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'is_pool', 'description')
|
||||
default_columns = ('pk', 'prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'description')
|
||||
row_attrs = {
|
||||
'class': lambda record: 'success' if not record.pk else '',
|
||||
}
|
||||
|
||||
|
||||
class PrefixDetailTable(PrefixTable):
|
||||
utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False)
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
utilization = tables.TemplateColumn(
|
||||
template_code=UTILIZATION_GRAPH,
|
||||
orderable=False
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
|
||||
class Meta(PrefixTable.Meta):
|
||||
fields = ('pk', 'prefix', 'status', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description')
|
||||
fields = (
|
||||
'pk', 'prefix', 'status', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'is_pool', 'description',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'prefix', 'status', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description',
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
@ -339,12 +404,27 @@ class PrefixDetailTable(PrefixTable):
|
||||
|
||||
class IPAddressTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
address = tables.TemplateColumn(IPADDRESS_LINK, verbose_name='IP Address')
|
||||
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
tenant = tables.TemplateColumn(template_code=TENANT_LINK)
|
||||
parent = tables.TemplateColumn(IPADDRESS_PARENT, orderable=False)
|
||||
interface = tables.Column(orderable=False)
|
||||
address = tables.TemplateColumn(
|
||||
template_code=IPADDRESS_LINK,
|
||||
verbose_name='IP Address'
|
||||
)
|
||||
vrf = tables.TemplateColumn(
|
||||
template_code=VRF_LINK,
|
||||
verbose_name='VRF'
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=TENANT_LINK
|
||||
)
|
||||
parent = tables.TemplateColumn(
|
||||
template_code=IPADDRESS_PARENT,
|
||||
orderable=False
|
||||
)
|
||||
interface = tables.Column(
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = IPAddress
|
||||
@ -358,22 +438,40 @@ class IPAddressTable(BaseTable):
|
||||
|
||||
class IPAddressDetailTable(IPAddressTable):
|
||||
nat_inside = tables.LinkColumn(
|
||||
'ipam:ipaddress', args=[Accessor('nat_inside.pk')], orderable=False, verbose_name='NAT (Inside)'
|
||||
viewname='ipam:ipaddress',
|
||||
args=[Accessor('nat_inside.pk')],
|
||||
orderable=False,
|
||||
verbose_name='NAT (Inside)'
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
|
||||
class Meta(IPAddressTable.Meta):
|
||||
fields = (
|
||||
'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'parent', 'interface', 'dns_name',
|
||||
'description',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'parent', 'interface', 'dns_name', 'description',
|
||||
)
|
||||
|
||||
|
||||
class IPAddressAssignTable(BaseTable):
|
||||
address = tables.TemplateColumn(IPADDRESS_ASSIGN_LINK, verbose_name='IP Address')
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
parent = tables.TemplateColumn(IPADDRESS_PARENT, orderable=False)
|
||||
interface = tables.Column(orderable=False)
|
||||
address = tables.TemplateColumn(
|
||||
template_code=IPADDRESS_ASSIGN_LINK,
|
||||
verbose_name='IP Address'
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
parent = tables.TemplateColumn(
|
||||
template_code=IPADDRESS_PARENT,
|
||||
orderable=False
|
||||
)
|
||||
interface = tables.Column(
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = IPAddress
|
||||
@ -385,10 +483,19 @@ class InterfaceIPAddressTable(BaseTable):
|
||||
"""
|
||||
List IP addresses assigned to a specific Interface.
|
||||
"""
|
||||
address = tables.LinkColumn(verbose_name='IP Address')
|
||||
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
tenant = tables.TemplateColumn(template_code=TENANT_LINK)
|
||||
address = tables.LinkColumn(
|
||||
verbose_name='IP Address'
|
||||
)
|
||||
vrf = tables.TemplateColumn(
|
||||
template_code=VRF_LINK,
|
||||
verbose_name='VRF'
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=TENANT_LINK
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = IPAddress
|
||||
@ -401,16 +508,24 @@ class InterfaceIPAddressTable(BaseTable):
|
||||
|
||||
class VLANGroupTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn(verbose_name='Name')
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
||||
vlan_count = tables.Column(verbose_name='VLANs')
|
||||
slug = tables.Column(verbose_name='Slug')
|
||||
actions = tables.TemplateColumn(template_code=VLANGROUP_ACTIONS, attrs={'td': {'class': 'text-right noprint'}},
|
||||
verbose_name='')
|
||||
name = tables.LinkColumn()
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
vlan_count = tables.Column(
|
||||
verbose_name='VLANs'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=VLANGROUP_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
verbose_name=''
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VLANGroup
|
||||
fields = ('pk', 'name', 'site', 'vlan_count', 'slug', 'description', 'actions')
|
||||
default_columns = ('pk', 'name', 'site', 'vlan_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -419,12 +534,27 @@ class VLANGroupTable(BaseTable):
|
||||
|
||||
class VLANTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
vid = tables.TemplateColumn(VLAN_LINK, verbose_name='ID')
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
group = tables.LinkColumn('ipam:vlangroup_vlans', args=[Accessor('group.pk')], verbose_name='Group')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
role = tables.TemplateColumn(VLAN_ROLE_LINK)
|
||||
vid = tables.TemplateColumn(
|
||||
template_code=VLAN_LINK,
|
||||
verbose_name='ID'
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
group = tables.LinkColumn(
|
||||
viewname='ipam:vlangroup_vlans',
|
||||
args=[Accessor('group.pk')]
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_code=VLAN_ROLE_LINK
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VLAN
|
||||
@ -435,16 +565,26 @@ class VLANTable(BaseTable):
|
||||
|
||||
|
||||
class VLANDetailTable(VLANTable):
|
||||
prefixes = tables.TemplateColumn(VLAN_PREFIXES, orderable=False, verbose_name='Prefixes')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
prefixes = tables.TemplateColumn(
|
||||
template_code=VLAN_PREFIXES,
|
||||
orderable=False,
|
||||
verbose_name='Prefixes'
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
|
||||
class Meta(VLANTable.Meta):
|
||||
fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description')
|
||||
|
||||
|
||||
class VLANMemberTable(BaseTable):
|
||||
parent = tables.LinkColumn(order_by=['device', 'virtual_machine'])
|
||||
name = tables.LinkColumn(verbose_name='Interface')
|
||||
parent = tables.LinkColumn(
|
||||
order_by=['device', 'virtual_machine']
|
||||
)
|
||||
name = tables.LinkColumn(
|
||||
verbose_name='Interface'
|
||||
)
|
||||
untagged = tables.TemplateColumn(
|
||||
template_code=VLAN_MEMBER_UNTAGGED,
|
||||
orderable=False
|
||||
@ -464,13 +604,29 @@ class InterfaceVLANTable(BaseTable):
|
||||
"""
|
||||
List VLANs assigned to a specific Interface.
|
||||
"""
|
||||
vid = tables.LinkColumn('ipam:vlan', args=[Accessor('pk')], verbose_name='ID')
|
||||
vid = tables.LinkColumn(
|
||||
viewname='ipam:vlan',
|
||||
args=[Accessor('pk')],
|
||||
verbose_name='ID'
|
||||
)
|
||||
tagged = BooleanColumn()
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
status = tables.TemplateColumn(STATUS_LABEL)
|
||||
role = tables.TemplateColumn(VLAN_ROLE_LINK)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
group = tables.Column(
|
||||
accessor=Accessor('group.name'),
|
||||
verbose_name='Group'
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=STATUS_LABEL
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_code=VLAN_ROLE_LINK
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VLAN
|
||||
@ -494,4 +650,5 @@ class ServiceTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Service
|
||||
fields = ('pk', 'name', 'parent', 'protocol', 'port', 'description')
|
||||
fields = ('pk', 'name', 'parent', 'protocol', 'port', 'ipaddresses', 'description')
|
||||
default_columns = ('pk', 'name', 'parent', 'protocol', 'port', 'description')
|
||||
|
@ -20,7 +20,7 @@ from dcim.models import (
|
||||
Cable, ConsolePort, Device, DeviceType, Interface, PowerPanel, PowerFeed, PowerPort, Rack, RackGroup, Site, VirtualChassis
|
||||
)
|
||||
from dcim.tables import (
|
||||
CableTable, DeviceDetailTable, DeviceTypeTable, PowerFeedTable, RackTable, RackGroupTable, SiteTable,
|
||||
CableTable, DeviceTable, DeviceTypeTable, PowerFeedTable, RackTable, RackGroupTable, SiteTable,
|
||||
VirtualChassisTable,
|
||||
)
|
||||
from extras.models import ObjectChange, ReportResult
|
||||
@ -44,7 +44,7 @@ SEARCH_TYPES = OrderedDict((
|
||||
# Circuits
|
||||
('provider', {
|
||||
'permission': 'circuits.view_provider',
|
||||
'queryset': Provider.objects.all(),
|
||||
'queryset': Provider.objects.annotate(count_circuits=Count('circuits')),
|
||||
'filterset': ProviderFilterSet,
|
||||
'table': ProviderTable,
|
||||
'url': 'circuits:provider_list',
|
||||
@ -93,7 +93,7 @@ SEARCH_TYPES = OrderedDict((
|
||||
'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6',
|
||||
),
|
||||
'filterset': DeviceFilterSet,
|
||||
'table': DeviceDetailTable,
|
||||
'table': DeviceTable,
|
||||
'url': 'dcim:device_list',
|
||||
}),
|
||||
('virtualchassis', {
|
||||
|
@ -448,4 +448,33 @@ $(document).ready(function() {
|
||||
$('a.image-preview').on('mouseout', function() {
|
||||
$('#image-preview-window').fadeOut('fast');
|
||||
});
|
||||
|
||||
// Rearrange options within a <select> list
|
||||
$('#move-option-up').bind('click', function() {
|
||||
var select_id = '#' + $(this).attr('data-target');
|
||||
$(select_id + ' option:selected').each(function () {
|
||||
var newPos = $(select_id + ' option').index(this) - 1;
|
||||
if (newPos > -1) {
|
||||
$(select_id + ' option').eq(newPos).before("<option value='" + $(this).val() + "' selected='selected'>" + $(this).text() + "</option>");
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#move-option-down').bind('click', function() {
|
||||
var select_id = '#' + $(this).attr('data-target');
|
||||
var countOptions = $(select_id + ' option').length;
|
||||
var countSelectedOptions = $(select_id + ' option:selected').length;
|
||||
$(select_id + ' option:selected').each(function () {
|
||||
var newPos = $(select_id + ' option').index(this) + countSelectedOptions;
|
||||
if (newPos < countOptions) {
|
||||
$(select_id + ' option').eq(newPos).after("<option value='" + $(this).val() + "' selected='selected'>" + $(this).text() + "</option>");
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#select-all-options').bind('click', function() {
|
||||
var select_id = '#' + $(this).attr('data-target');
|
||||
$(select_id + ' option').prop('selected',true);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -20,14 +20,19 @@ SECRETROLE_ACTIONS = """
|
||||
class SecretRoleTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
secret_count = tables.Column(verbose_name='Secrets')
|
||||
secret_count = tables.Column(
|
||||
verbose_name='Secrets'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=SECRETROLE_ACTIONS, attrs={'td': {'class': 'text-right noprint'}}, verbose_name=''
|
||||
template_code=SECRETROLE_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
verbose_name=''
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = SecretRole
|
||||
fields = ('pk', 'name', 'secret_count', 'description', 'slug', 'actions')
|
||||
fields = ('pk', 'name', 'secret_count', 'description', 'slug', 'users', 'groups', 'actions')
|
||||
default_columns = ('pk', 'name', 'secret_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -40,4 +45,5 @@ class SecretTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Secret
|
||||
fields = ('pk', 'device', 'role', 'name', 'last_updated')
|
||||
fields = ('pk', 'device', 'role', 'name', 'last_updated', 'hash')
|
||||
default_columns = ('pk', 'device', 'role', 'name', 'last_updated')
|
||||
|
28
netbox/templates/inc/table_config_form.html
Normal file
28
netbox/templates/inc/table_config_form.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% load form_helpers %}
|
||||
<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">×</span></button>
|
||||
<h4 class="modal-title">Table Configuration</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% render_form table_config_form %}
|
||||
<div class="row">
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
<a class="btn btn-primary btn-xs" id="move-option-up" data-target="id_columns"><i class="fa fa-arrow-up"></i> Move up</a>
|
||||
<a class="btn btn-primary btn-xs" id="move-option-down" data-target="id_columns"><i class="fa fa-arrow-down"></i> Move down</a>
|
||||
<a class="btn btn-success btn-xs" id="select-all-options" data-target="id_columns"><i class="fa fa-ellipsis-v"></i> Select all</a>
|
||||
</div>
|
||||
</div>
|
||||
<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="Reset" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -5,6 +5,9 @@
|
||||
{% block content %}
|
||||
<div class="pull-right noprint">
|
||||
{% block buttons %}{% endblock %}
|
||||
{% if table_config_form %}
|
||||
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#tableconfig" title="Configure table"><i class="fa fa-cog"></i> Configure</button>
|
||||
{% endif %}
|
||||
{% if permissions.add and 'add' in action_buttons %}
|
||||
{% add_button content_type.model_class|url_name:"add" %}
|
||||
{% endif %}
|
||||
@ -68,6 +71,9 @@
|
||||
{% endwith %}
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
<div class="clearfix"></div>
|
||||
{% if table_config_form %}
|
||||
{% include 'inc/table_config_form.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if filter_form %}
|
||||
<div class="col-md-3 noprint">
|
||||
|
@ -44,7 +44,6 @@ class TenantGroupTable(BaseTable):
|
||||
tenant_count = tables.Column(
|
||||
verbose_name='Tenants'
|
||||
)
|
||||
slug = tables.Column()
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=TENANTGROUP_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -54,6 +53,7 @@ class TenantGroupTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = TenantGroup
|
||||
fields = ('pk', 'name', 'tenant_count', 'description', 'slug', 'actions')
|
||||
default_columns = ('pk', 'name', 'tenant_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -66,4 +66,5 @@ class TenantTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Tenant
|
||||
fields = ('pk', 'name', 'group', 'description')
|
||||
fields = ('pk', 'name', 'slug', 'group', 'description')
|
||||
default_columns = ('pk', 'name', 'group', 'description')
|
||||
|
@ -108,7 +108,7 @@ class UserConfig(models.Model):
|
||||
|
||||
userconfig.clear('foo.bar.baz')
|
||||
|
||||
A KeyError is raised in the event any key along the path does not exist.
|
||||
Invalid keys will be ignored silently.
|
||||
|
||||
:param path: Dotted path to the configuration key. For example, 'foo.bar' deletes self.data['foo']['bar'].
|
||||
:param commit: If true, the UserConfig instance will be saved once the new value has been applied.
|
||||
@ -117,11 +117,13 @@ class UserConfig(models.Model):
|
||||
keys = path.split('.')
|
||||
|
||||
for key in keys[:-1]:
|
||||
if key in d and type(d[key]) is dict:
|
||||
if key not in d:
|
||||
break
|
||||
if type(d[key]) is dict:
|
||||
d = d[key]
|
||||
|
||||
key = keys[-1]
|
||||
del(d[key])
|
||||
d.pop(key, None) # Avoid a KeyError on invalid keys
|
||||
|
||||
if commit:
|
||||
self.save()
|
||||
|
0
netbox/users/tests/__init__.py
Normal file
0
netbox/users/tests/__init__.py
Normal file
@ -104,6 +104,5 @@ class UserConfigTest(TestCase):
|
||||
self.assertTrue('foo' not in userconfig.data['b'])
|
||||
self.assertEqual(userconfig.data['b']['bar'], 102)
|
||||
|
||||
# Clear an invalid value
|
||||
with self.assertRaises(KeyError):
|
||||
userconfig.clear('invalid')
|
||||
# Clear a non-existing value; should fail silently
|
||||
userconfig.clear('invalid')
|
||||
|
@ -665,7 +665,10 @@ class BootstrapMixin(forms.BaseForm):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
exempt_widgets = [
|
||||
forms.CheckboxInput, forms.ClearableFileInput, forms.FileInput, forms.RadioSelect
|
||||
forms.CheckboxInput,
|
||||
forms.ClearableFileInput,
|
||||
forms.FileInput,
|
||||
forms.RadioSelect
|
||||
]
|
||||
|
||||
for field_name, field in self.fields.items():
|
||||
@ -752,3 +755,23 @@ class ImportForm(BootstrapMixin, forms.Form):
|
||||
raise forms.ValidationError({
|
||||
'data': "Invalid YAML data: {}".format(err)
|
||||
})
|
||||
|
||||
|
||||
class TableConfigForm(BootstrapMixin, forms.Form):
|
||||
"""
|
||||
Form for configuring user's table preferences.
|
||||
"""
|
||||
columns = forms.MultipleChoiceField(
|
||||
choices=[],
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={'size': 10}
|
||||
),
|
||||
help_text="Use the buttons below to arrange columns in the desired order, then select all columns to display."
|
||||
)
|
||||
|
||||
def __init__(self, table, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Initialize columns field based on table attributes
|
||||
self.fields['columns'].choices = table.configurable_columns
|
||||
self.fields['columns'].initial = table.visible_columns
|
||||
|
@ -1,4 +1,7 @@
|
||||
import django_tables2 as tables
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import ForeignKey
|
||||
from django_tables2.data import TableQuerysetData
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
@ -6,17 +9,73 @@ class BaseTable(tables.Table):
|
||||
"""
|
||||
Default table for object lists
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
class Meta:
|
||||
attrs = {
|
||||
'class': 'table table-hover table-headings',
|
||||
}
|
||||
|
||||
def __init__(self, *args, columns=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Set default empty_text if none was provided
|
||||
if self.empty_text is None:
|
||||
self.empty_text = 'No {} found'.format(self._meta.model._meta.verbose_name_plural)
|
||||
|
||||
class Meta:
|
||||
attrs = {
|
||||
'class': 'table table-hover table-headings',
|
||||
}
|
||||
# Hide non-default columns
|
||||
default_columns = getattr(self.Meta, 'default_columns', list())
|
||||
if default_columns:
|
||||
for column in self.columns:
|
||||
if column.name not in default_columns:
|
||||
self.columns.hide(column.name)
|
||||
|
||||
# Apply custom column ordering
|
||||
if columns is not None:
|
||||
pk = self.base_columns.pop('pk', None)
|
||||
actions = self.base_columns.pop('actions', None)
|
||||
|
||||
for name, column in self.base_columns.items():
|
||||
if name in columns:
|
||||
self.columns.show(name)
|
||||
else:
|
||||
self.columns.hide(name)
|
||||
self.sequence = columns
|
||||
|
||||
# Always include PK and actions column, if defined on the table
|
||||
if pk:
|
||||
self.base_columns['pk'] = pk
|
||||
self.sequence.insert(0, 'pk')
|
||||
if actions:
|
||||
self.base_columns['actions'] = actions
|
||||
self.sequence.append('actions')
|
||||
|
||||
# Dynamically update the table's QuerySet to ensure related fields are pre-fetched
|
||||
if isinstance(self.data, TableQuerysetData):
|
||||
model = getattr(self.Meta, 'model')
|
||||
prefetch_fields = []
|
||||
for column in self.columns:
|
||||
if column.visible:
|
||||
field_path = column.accessor.split('.')
|
||||
try:
|
||||
model_field = model._meta.get_field(field_path[0])
|
||||
if isinstance(model_field, ForeignKey):
|
||||
prefetch_fields.append('__'.join(field_path))
|
||||
except FieldDoesNotExist:
|
||||
pass
|
||||
self.data.data = self.data.data.prefetch_related(None).prefetch_related(*prefetch_fields)
|
||||
|
||||
@property
|
||||
def configurable_columns(self):
|
||||
selected_columns = [
|
||||
(name, self.columns[name].verbose_name) for name in self.sequence if name not in ['pk', 'actions']
|
||||
]
|
||||
available_columns = [
|
||||
(name, column.verbose_name) for name, column in self.columns.items() if name not in self.sequence and name not in ['pk', 'actions']
|
||||
]
|
||||
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):
|
||||
|
@ -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
|
||||
@ -164,7 +164,8 @@ class ObjectListView(View):
|
||||
permissions[action] = request.user.has_perm(perm_name)
|
||||
|
||||
# Construct the table based on the user's permissions
|
||||
table = self.table(self.queryset)
|
||||
columns = request.user.config.get(f"tables.{self.table.__name__}.columns")
|
||||
table = self.table(self.queryset, columns=columns)
|
||||
if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']):
|
||||
table.columns.show('pk')
|
||||
|
||||
@ -180,12 +181,29 @@ class ObjectListView(View):
|
||||
'table': table,
|
||||
'permissions': permissions,
|
||||
'action_buttons': self.action_buttons,
|
||||
'table_config_form': TableConfigForm(table=table),
|
||||
'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None,
|
||||
}
|
||||
context.update(self.extra_context())
|
||||
|
||||
return render(request, self.template_name, context)
|
||||
|
||||
def post(self, request):
|
||||
|
||||
# Update the user's table configuration
|
||||
table = self.table(self.queryset)
|
||||
form = TableConfigForm(table=table, data=request.POST)
|
||||
preference_name = f"tables.{self.table.__name__}.columns"
|
||||
|
||||
if form.is_valid():
|
||||
if 'set' in request.POST:
|
||||
request.user.config.set(preference_name, form.cleaned_data['columns'], commit=True)
|
||||
elif 'clear' in request.POST:
|
||||
request.user.config.clear(preference_name, commit=True)
|
||||
messages.success(request, "Your preferences have been updated.")
|
||||
|
||||
return redirect(request.get_full_path())
|
||||
|
||||
def alter_queryset(self, request):
|
||||
# .all() is necessary to avoid caching queries
|
||||
return self.queryset.all()
|
||||
|
@ -46,7 +46,9 @@ VIRTUALMACHINE_PRIMARY_IP = """
|
||||
class ClusterTypeTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
cluster_count = tables.Column(verbose_name='Clusters')
|
||||
cluster_count = tables.Column(
|
||||
verbose_name='Clusters'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=CLUSTERTYPE_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -55,7 +57,8 @@ class ClusterTypeTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ClusterType
|
||||
fields = ('pk', 'name', 'cluster_count', 'description', 'actions')
|
||||
fields = ('pk', 'name', 'slug', 'cluster_count', 'description', 'actions')
|
||||
default_columns = ('pk', 'name', 'cluster_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -65,7 +68,9 @@ class ClusterTypeTable(BaseTable):
|
||||
class ClusterGroupTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
cluster_count = tables.Column(verbose_name='Clusters')
|
||||
cluster_count = tables.Column(
|
||||
verbose_name='Clusters'
|
||||
)
|
||||
actions = tables.TemplateColumn(
|
||||
template_code=CLUSTERGROUP_ACTIONS,
|
||||
attrs={'td': {'class': 'text-right noprint'}},
|
||||
@ -74,7 +79,8 @@ class ClusterGroupTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = ClusterGroup
|
||||
fields = ('pk', 'name', 'cluster_count', 'description', 'actions')
|
||||
fields = ('pk', 'name', 'slug', 'cluster_count', 'description', 'actions')
|
||||
default_columns = ('pk', 'name', 'cluster_count', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
@ -84,10 +90,24 @@ class ClusterGroupTable(BaseTable):
|
||||
class ClusterTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||
device_count = tables.Column(accessor=Accessor('devices.count'), orderable=False, verbose_name='Devices')
|
||||
vm_count = tables.Column(accessor=Accessor('virtual_machines.count'), orderable=False, verbose_name='VMs')
|
||||
tenant = tables.LinkColumn(
|
||||
viewname='tenancy:tenant',
|
||||
args=[Accessor('tenant.slug')]
|
||||
)
|
||||
site = tables.LinkColumn(
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site.slug')]
|
||||
)
|
||||
device_count = tables.Column(
|
||||
accessor=Accessor('devices.count'),
|
||||
orderable=False,
|
||||
verbose_name='Devices'
|
||||
)
|
||||
vm_count = tables.Column(
|
||||
accessor=Accessor('virtual_machines.count'),
|
||||
orderable=False,
|
||||
verbose_name='VMs'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Cluster
|
||||
@ -101,10 +121,19 @@ class ClusterTable(BaseTable):
|
||||
class VirtualMachineTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
status = tables.TemplateColumn(template_code=VIRTUALMACHINE_STATUS)
|
||||
cluster = tables.LinkColumn('virtualization:cluster', args=[Accessor('cluster.pk')])
|
||||
role = tables.TemplateColumn(VIRTUALMACHINE_ROLE)
|
||||
tenant = tables.TemplateColumn(template_code=COL_TENANT)
|
||||
status = tables.TemplateColumn(
|
||||
template_code=VIRTUALMACHINE_STATUS
|
||||
)
|
||||
cluster = tables.LinkColumn(
|
||||
viewname='virtualization:cluster',
|
||||
args=[Accessor('cluster.pk')]
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_code=VIRTUALMACHINE_ROLE
|
||||
)
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VirtualMachine
|
||||
@ -112,13 +141,31 @@ class VirtualMachineTable(BaseTable):
|
||||
|
||||
|
||||
class VirtualMachineDetailTable(VirtualMachineTable):
|
||||
primary_ip4 = tables.LinkColumn(
|
||||
viewname='ipam:ipaddress',
|
||||
args=[Accessor('primary_ip4.pk')],
|
||||
verbose_name='IPv4 Address'
|
||||
)
|
||||
primary_ip6 = tables.LinkColumn(
|
||||
viewname='ipam:ipaddress',
|
||||
args=[Accessor('primary_ip6.pk')],
|
||||
verbose_name='IPv6 Address'
|
||||
)
|
||||
primary_ip = tables.TemplateColumn(
|
||||
orderable=False, verbose_name='IP Address', template_code=VIRTUALMACHINE_PRIMARY_IP
|
||||
orderable=False,
|
||||
verbose_name='IP Address',
|
||||
template_code=VIRTUALMACHINE_PRIMARY_IP
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = VirtualMachine
|
||||
fields = ('pk', 'name', 'status', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip')
|
||||
fields = (
|
||||
'pk', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'primary_ip4',
|
||||
'primary_ip6', 'primary_ip',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'name', 'status', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip',
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user