Merge pull request #4790 from netbox-community/4788-component-views

#4788: Add individual views for device components
This commit is contained in:
Jeremy Stretch 2020-06-25 13:38:09 -04:00 committed by GitHub
commit 6d23d9ebb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1148 additions and 496 deletions

View File

@ -14,6 +14,7 @@ NetBox v2.9 replaces Django's built-in permissions framework with one that suppo
* [#3703](https://github.com/netbox-community/netbox/issues/3703) - Tags must be created administratively before being assigned to an object * [#3703](https://github.com/netbox-community/netbox/issues/3703) - Tags must be created administratively before being assigned to an object
* [#4615](https://github.com/netbox-community/netbox/issues/4615) - Add `label` field for all device components * [#4615](https://github.com/netbox-community/netbox/issues/4615) - Add `label` field for all device components
* [#4742](https://github.com/netbox-community/netbox/issues/4742) - Add tagging for cables, power panels, and rack reservations * [#4742](https://github.com/netbox-community/netbox/issues/4742) - Add tagging for cables, power panels, and rack reservations
* [#4788](https://github.com/netbox-community/netbox/issues/4788) - Add dedicated views for all device components
### Configuration Changes ### Configuration Changes

View File

@ -268,7 +268,7 @@ class ConsolePort(CableTermination, ComponentModel):
unique_together = ('device', 'name') unique_together = ('device', 'name')
def get_absolute_url(self): def get_absolute_url(self):
return self.device.get_absolute_url() return reverse('dcim:consoleport', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
@ -325,7 +325,7 @@ class ConsoleServerPort(CableTermination, ComponentModel):
unique_together = ('device', 'name') unique_together = ('device', 'name')
def get_absolute_url(self): def get_absolute_url(self):
return self.device.get_absolute_url() return reverse('dcim:consoleserverport', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
@ -408,7 +408,7 @@ class PowerPort(CableTermination, ComponentModel):
unique_together = ('device', 'name') unique_together = ('device', 'name')
def get_absolute_url(self): def get_absolute_url(self):
return self.device.get_absolute_url() return reverse('dcim:powerport', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
@ -560,7 +560,7 @@ class PowerOutlet(CableTermination, ComponentModel):
unique_together = ('device', 'name') unique_together = ('device', 'name')
def get_absolute_url(self): def get_absolute_url(self):
return self.device.get_absolute_url() return reverse('dcim:poweroutlet', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
@ -881,6 +881,9 @@ class FrontPort(CableTermination, ComponentModel):
def __str__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self):
return reverse('dcim:frontport', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
self.device.identifier, self.device.identifier,
@ -946,6 +949,9 @@ class RearPort(CableTermination, ComponentModel):
def __str__(self): def __str__(self):
return self.name return self.name
def get_absolute_url(self):
return reverse('dcim:rearport', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (
self.device.identifier, self.device.identifier,
@ -1005,7 +1011,7 @@ class DeviceBay(ComponentModel):
return '{} - {}'.format(self.device.name, self.name) return '{} - {}'.format(self.device.name, self.name)
def get_absolute_url(self): def get_absolute_url(self):
return self.device.get_absolute_url() return reverse('dcim:devicebay', kwargs={'pk': self.pk})
def to_csv(self): def to_csv(self):
return ( return (

View File

@ -490,18 +490,6 @@ class ConsolePortTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class ConsolePortImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = ConsolePort
fields = ('device', 'name', 'description')
empty_text = False
class ConsoleServerPortTemplateTable(ComponentTemplateTable): class ConsoleServerPortTemplateTable(ComponentTemplateTable):
actions = tables.TemplateColumn( actions = tables.TemplateColumn(
template_code=get_component_template_actions('consoleserverporttemplate'), template_code=get_component_template_actions('consoleserverporttemplate'),
@ -515,18 +503,6 @@ class ConsoleServerPortTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class ConsoleServerPortImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = ConsoleServerPort
fields = ('device', 'name', 'description')
empty_text = False
class PowerPortTemplateTable(ComponentTemplateTable): class PowerPortTemplateTable(ComponentTemplateTable):
actions = tables.TemplateColumn( actions = tables.TemplateColumn(
template_code=get_component_template_actions('powerporttemplate'), template_code=get_component_template_actions('powerporttemplate'),
@ -540,18 +516,6 @@ class PowerPortTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class PowerPortImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = PowerPort
fields = ('device', 'name', 'description', 'maximum_draw', 'allocated_draw')
empty_text = False
class PowerOutletTemplateTable(ComponentTemplateTable): class PowerOutletTemplateTable(ComponentTemplateTable):
actions = tables.TemplateColumn( actions = tables.TemplateColumn(
template_code=get_component_template_actions('poweroutlettemplate'), template_code=get_component_template_actions('poweroutlettemplate'),
@ -565,18 +529,6 @@ class PowerOutletTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class PowerOutletImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = PowerOutlet
fields = ('device', 'name', 'description', 'power_port', 'feed_leg')
empty_text = False
class InterfaceTemplateTable(ComponentTemplateTable): class InterfaceTemplateTable(ComponentTemplateTable):
mgmt_only = BooleanColumn( mgmt_only = BooleanColumn(
verbose_name='Management Only' verbose_name='Management Only'
@ -593,20 +545,6 @@ class InterfaceTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class InterfaceImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = Interface
fields = (
'device', 'name', 'description', 'lag', 'type', 'enabled', 'mac_address', 'mtu', 'mgmt_only', 'mode',
)
empty_text = False
class FrontPortTemplateTable(ComponentTemplateTable): class FrontPortTemplateTable(ComponentTemplateTable):
rear_port_position = tables.Column( rear_port_position = tables.Column(
verbose_name='Position' verbose_name='Position'
@ -623,18 +561,6 @@ class FrontPortTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class FrontPortImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = FrontPort
fields = ('device', 'name', 'description', 'type', 'rear_port', 'rear_port_position')
empty_text = False
class RearPortTemplateTable(ComponentTemplateTable): class RearPortTemplateTable(ComponentTemplateTable):
actions = tables.TemplateColumn( actions = tables.TemplateColumn(
template_code=get_component_template_actions('rearporttemplate'), template_code=get_component_template_actions('rearporttemplate'),
@ -648,18 +574,6 @@ class RearPortTemplateTable(ComponentTemplateTable):
empty_text = "None" empty_text = "None"
class RearPortImportTable(BaseTable):
device = tables.LinkColumn(
viewname='dcim:device',
args=[Accessor('device.pk')]
)
class Meta(BaseTable.Meta):
model = RearPort
fields = ('device', 'name', 'description', 'type', 'position')
empty_text = False
class DeviceBayTemplateTable(ComponentTemplateTable): class DeviceBayTemplateTable(ComponentTemplateTable):
actions = tables.TemplateColumn( actions = tables.TemplateColumn(
template_code=get_component_template_actions('devicebaytemplate'), template_code=get_component_template_actions('devicebaytemplate'),
@ -855,144 +769,94 @@ class DeviceImportTable(BaseTable):
# Device components # Device components
# #
class DeviceComponentDetailTable(BaseTable): class DeviceComponentTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
device = tables.LinkColumn() device = tables.Column(
name = tables.Column(order_by=('_name',)) linkify=True
cable = tables.LinkColumn() )
name = tables.Column(
linkify=True,
order_by=('_name',)
)
cable = tables.Column(
linkify=True
)
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
order_by = ('device', 'name') order_by = ('device', 'name')
fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable')
sequence = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable')
class ConsolePortTable(BaseTable): class ConsolePortTable(DeviceComponentTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta): class Meta(DeviceComponentTable.Meta):
model = ConsolePort model = ConsolePort
fields = ('name', 'label', 'type') fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
class ConsolePortDetailTable(DeviceComponentDetailTable): class ConsoleServerPortTable(DeviceComponentTable):
class Meta(DeviceComponentDetailTable.Meta, ConsolePortTable.Meta): class Meta(DeviceComponentTable.Meta):
pass
class ConsoleServerPortTable(BaseTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta):
model = ConsoleServerPort model = ConsoleServerPort
fields = ('name', 'label', 'description') fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
class ConsoleServerPortDetailTable(DeviceComponentDetailTable): class PowerPortTable(DeviceComponentTable):
class Meta(DeviceComponentDetailTable.Meta, ConsoleServerPortTable.Meta): class Meta(DeviceComponentTable.Meta):
pass
class PowerPortTable(BaseTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta):
model = PowerPort model = PowerPort
fields = ('name', 'label', 'type') fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'maximum_draw', 'allocated_draw', 'cable')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
class PowerPortDetailTable(DeviceComponentDetailTable): class PowerOutletTable(DeviceComponentTable):
class Meta(DeviceComponentDetailTable.Meta, PowerPortTable.Meta): class Meta(DeviceComponentTable.Meta):
pass
class PowerOutletTable(BaseTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta):
model = PowerOutlet model = PowerOutlet
fields = ('name', 'label', 'type', 'description') fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'cable')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description')
class PowerOutletDetailTable(DeviceComponentDetailTable): class InterfaceTable(DeviceComponentTable):
class Meta(DeviceComponentDetailTable.Meta, PowerOutletTable.Meta):
pass
class InterfaceTable(BaseTable):
class Meta(BaseTable.Meta):
model = Interface
fields = ('name', 'label', 'type', 'lag', 'enabled', 'mgmt_only', 'description')
class InterfaceDetailTable(DeviceComponentDetailTable):
enabled = BooleanColumn() enabled = BooleanColumn()
class Meta(DeviceComponentDetailTable.Meta, InterfaceTable.Meta): class Meta(DeviceComponentTable.Meta):
fields = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description', 'cable') model = Interface
sequence = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description', 'cable') fields = (
'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'description', 'cable',
)
default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
class FrontPortTable(BaseTable): class FrontPortTable(DeviceComponentTable):
name = tables.Column(order_by=('_name',)) rear_port_position = tables.Column(
verbose_name='Position'
)
class Meta(BaseTable.Meta): class Meta(DeviceComponentTable.Meta):
model = FrontPort model = FrontPort
fields = ('name', 'label', 'type', 'rear_port', 'rear_port_position', 'description') fields = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable')
empty_text = "None" default_columns = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description')
class FrontPortDetailTable(DeviceComponentDetailTable): class RearPortTable(DeviceComponentTable):
class Meta(DeviceComponentDetailTable.Meta, FrontPortTable.Meta): class Meta(DeviceComponentTable.Meta):
pass
class RearPortTable(BaseTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta):
model = RearPort model = RearPort
fields = ('name', 'label', 'type', 'positions', 'description') fields = ('pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable')
empty_text = "None" default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
class RearPortDetailTable(DeviceComponentDetailTable): class DeviceBayTable(DeviceComponentTable):
installed_device = tables.Column(
linkify=True
)
class Meta(DeviceComponentDetailTable.Meta, RearPortTable.Meta): class Meta(DeviceComponentTable.Meta):
pass
class DeviceBayTable(BaseTable):
name = tables.Column(order_by=('_name',))
class Meta(BaseTable.Meta):
model = DeviceBay model = DeviceBay
fields = ('name', 'label', 'description')
class DeviceBayDetailTable(DeviceComponentDetailTable):
installed_device = tables.LinkColumn()
class Meta(DeviceBayTable.Meta):
fields = ('pk', 'device', 'name', 'label', 'installed_device', 'description') fields = ('pk', 'device', 'name', 'label', 'installed_device', 'description')
sequence = ('pk', 'device', 'name', 'label', 'installed_device', 'description') default_columns = ('pk', 'device', 'name', 'label', 'installed_device', 'description')
exclude = ('cable',)
class DeviceBayImportTable(BaseTable):
device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
installed_device = tables.LinkColumn('dcim:device', args=[Accessor('installed_device.pk')], verbose_name='Installed Device')
class Meta(BaseTable.Meta):
model = DeviceBay
fields = ('device', 'name', 'installed_device', 'description')
empty_text = False
# #

View File

@ -1194,10 +1194,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
) )
class InterfaceTestCase( class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
ViewTestCases.GetObjectViewTestCase,
ViewTestCases.DeviceComponentViewTestCase,
):
model = Interface model = Interface
@classmethod @classmethod
@ -1425,7 +1422,16 @@ class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
) )
class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase): # TODO: Convert to DeviceComponentViewTestCase?
class InventoryItemTestCase(
ViewTestCases.EditObjectViewTestCase,
ViewTestCases.DeleteObjectViewTestCase,
ViewTestCases.ListObjectsViewTestCase,
ViewTestCases.BulkCreateObjectsViewTestCase,
ViewTestCases.BulkImportObjectsViewTestCase,
ViewTestCases.BulkEditObjectsViewTestCase,
ViewTestCases.BulkDeleteObjectsViewTestCase
):
model = InventoryItem model = InventoryItem
@classmethod @classmethod

View File

@ -4,9 +4,9 @@ from extras.views import ObjectChangeLogView, ImageAttachmentEditView
from ipam.views import ServiceEditView from ipam.views import ServiceEditView
from . import views from . import views
from .models import ( from .models import (
Cable, ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, FrontPort, Interface, Manufacturer, Platform, Cable, ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, DeviceType, FrontPort, Interface,
PowerFeed, PowerPanel, PowerPort, PowerOutlet, Rack, RackGroup, RackReservation, RackRole, RearPort, Region, Site, Manufacturer, Platform, PowerFeed, PowerPanel, PowerPort, PowerOutlet, Rack, RackGroup, RackReservation, RackRole,
VirtualChassis, RearPort, Region, Site, VirtualChassis,
) )
app_name = 'dcim' app_name = 'dcim'
@ -189,10 +189,12 @@ urlpatterns = [
path('console-ports/edit/', views.ConsolePortBulkEditView.as_view(), name='consoleport_bulk_edit'), path('console-ports/edit/', views.ConsolePortBulkEditView.as_view(), name='consoleport_bulk_edit'),
# TODO: Bulk rename, disconnect views for ConsolePorts # TODO: Bulk rename, disconnect views for ConsolePorts
path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'), path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
path('console-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}), path('console-ports/<int:pk>/', views.ConsolePortView.as_view(), name='consoleport'),
path('console-ports/<int:pk>/edit/', views.ConsolePortEditView.as_view(), name='consoleport_edit'), path('console-ports/<int:pk>/edit/', views.ConsolePortEditView.as_view(), name='consoleport_edit'),
path('console-ports/<int:pk>/delete/', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'), path('console-ports/<int:pk>/delete/', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'),
path('console-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='consoleport_changelog', kwargs={'model': ConsolePort}),
path('console-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}), path('console-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}),
path('console-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}),
path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'), path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
# Console server ports # Console server ports
@ -203,10 +205,12 @@ urlpatterns = [
path('console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'), path('console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
path('console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'), path('console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
path('console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'), path('console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
path('console-server-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}), path('console-server-ports/<int:pk>/', views.ConsoleServerPortView.as_view(), name='consoleserverport'),
path('console-server-ports/<int:pk>/edit/', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'), path('console-server-ports/<int:pk>/edit/', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'),
path('console-server-ports/<int:pk>/delete/', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'), path('console-server-ports/<int:pk>/delete/', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'),
path('console-server-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='consoleserverport_changelog', kwargs={'model': ConsoleServerPort}),
path('console-server-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}), path('console-server-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}),
path('console-server-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}),
path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'), path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
# Power ports # Power ports
@ -216,10 +220,12 @@ urlpatterns = [
path('power-ports/edit/', views.PowerPortBulkEditView.as_view(), name='powerport_bulk_edit'), path('power-ports/edit/', views.PowerPortBulkEditView.as_view(), name='powerport_bulk_edit'),
# TODO: Bulk rename, disconnect views for PowerPorts # TODO: Bulk rename, disconnect views for PowerPorts
path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'), path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
path('power-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}), path('power-ports/<int:pk>/', views.PowerPortView.as_view(), name='powerport'),
path('power-ports/<int:pk>/edit/', views.PowerPortEditView.as_view(), name='powerport_edit'), path('power-ports/<int:pk>/edit/', views.PowerPortEditView.as_view(), name='powerport_edit'),
path('power-ports/<int:pk>/delete/', views.PowerPortDeleteView.as_view(), name='powerport_delete'), path('power-ports/<int:pk>/delete/', views.PowerPortDeleteView.as_view(), name='powerport_delete'),
path('power-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='powerport_changelog', kwargs={'model': PowerPort}),
path('power-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}), path('power-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}),
path('power-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}),
path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'), path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
# Power outlets # Power outlets
@ -230,10 +236,12 @@ urlpatterns = [
path('power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'), path('power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
path('power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'), path('power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
path('power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'), path('power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
path('power-outlets/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}), path('power-outlets/<int:pk>/', views.PowerOutletView.as_view(), name='poweroutlet'),
path('power-outlets/<int:pk>/edit/', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'), path('power-outlets/<int:pk>/edit/', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'),
path('power-outlets/<int:pk>/delete/', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'), path('power-outlets/<int:pk>/delete/', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'),
path('power-outlets/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='poweroutlet_changelog', kwargs={'model': PowerOutlet}),
path('power-outlets/<int:pk>/trace/', views.CableTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}), path('power-outlets/<int:pk>/trace/', views.CableTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}),
path('power-outlets/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}),
path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'), path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
# Interfaces # Interfaces
@ -244,12 +252,12 @@ urlpatterns = [
path('interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'), path('interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
path('interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'), path('interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
path('interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'), path('interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
path('interfaces/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}),
path('interfaces/<int:pk>/', views.InterfaceView.as_view(), name='interface'), path('interfaces/<int:pk>/', views.InterfaceView.as_view(), name='interface'),
path('interfaces/<int:pk>/edit/', views.InterfaceEditView.as_view(), name='interface_edit'), path('interfaces/<int:pk>/edit/', views.InterfaceEditView.as_view(), name='interface_edit'),
path('interfaces/<int:pk>/delete/', views.InterfaceDeleteView.as_view(), name='interface_delete'), path('interfaces/<int:pk>/delete/', views.InterfaceDeleteView.as_view(), name='interface_delete'),
path('interfaces/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}), path('interfaces/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}),
path('interfaces/<int:pk>/trace/', views.CableTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}), path('interfaces/<int:pk>/trace/', views.CableTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}),
path('interfaces/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}),
path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'), path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
# Front ports # Front ports
@ -260,10 +268,12 @@ urlpatterns = [
path('front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'), path('front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'),
path('front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'), path('front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
path('front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'), path('front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
path('front-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}), path('front-ports/<int:pk>/', views.FrontPortView.as_view(), name='frontport'),
path('front-ports/<int:pk>/edit/', views.FrontPortEditView.as_view(), name='frontport_edit'), path('front-ports/<int:pk>/edit/', views.FrontPortEditView.as_view(), name='frontport_edit'),
path('front-ports/<int:pk>/delete/', views.FrontPortDeleteView.as_view(), name='frontport_delete'), path('front-ports/<int:pk>/delete/', views.FrontPortDeleteView.as_view(), name='frontport_delete'),
path('front-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='frontport_changelog', kwargs={'model': FrontPort}),
path('front-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}), path('front-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}),
path('front-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}),
# path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'), # path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
# Rear ports # Rear ports
@ -274,10 +284,12 @@ urlpatterns = [
path('rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'), path('rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'),
path('rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'), path('rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
path('rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'), path('rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
path('rear-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}), path('rear-ports/<int:pk>/', views.RearPortView.as_view(), name='rearport'),
path('rear-ports/<int:pk>/edit/', views.RearPortEditView.as_view(), name='rearport_edit'), path('rear-ports/<int:pk>/edit/', views.RearPortEditView.as_view(), name='rearport_edit'),
path('rear-ports/<int:pk>/delete/', views.RearPortDeleteView.as_view(), name='rearport_delete'), path('rear-ports/<int:pk>/delete/', views.RearPortDeleteView.as_view(), name='rearport_delete'),
path('rear-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rearport_changelog', kwargs={'model': RearPort}),
path('rear-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}), path('rear-ports/<int:pk>/trace/', views.CableTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}),
path('rear-ports/<int:termination_a_id>/connect/<str:termination_b_type>/', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}),
path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'), path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
# Device bays # Device bays
@ -287,8 +299,10 @@ urlpatterns = [
path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'), path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'),
path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'), path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'), path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
path('device-bays/<int:pk>/', views.DeviceBayView.as_view(), name='devicebay'),
path('device-bays/<int:pk>/edit/', views.DeviceBayEditView.as_view(), name='devicebay_edit'), path('device-bays/<int:pk>/edit/', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
path('device-bays/<int:pk>/delete/', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'), path('device-bays/<int:pk>/delete/', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
path('device-bays/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='devicebay_changelog', kwargs={'model': DeviceBay}),
path('device-bays/<int:pk>/populate/', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'), path('device-bays/<int:pk>/populate/', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'),
path('device-bays/<int:pk>/depopulate/', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'), path('device-bays/<int:pk>/depopulate/', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'),
path('devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'), path('devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),

View File

@ -1158,13 +1158,17 @@ class DeviceBulkDeleteView(BulkDeleteView):
# #
class ConsolePortListView(ObjectListView): class ConsolePortListView(ObjectListView):
queryset = ConsolePort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = ConsolePort.objects.prefetch_related('device', 'cable')
filterset = filters.ConsolePortFilterSet filterset = filters.ConsolePortFilterSet
filterset_form = forms.ConsolePortFilterForm filterset_form = forms.ConsolePortFilterForm
table = tables.ConsolePortDetailTable table = tables.ConsolePortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class ConsolePortView(ObjectView):
queryset = ConsolePort.objects.all()
class ConsolePortCreateView(ComponentCreateView): class ConsolePortCreateView(ComponentCreateView):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
form = forms.ConsolePortCreateForm form = forms.ConsolePortCreateForm
@ -1184,7 +1188,7 @@ class ConsolePortDeleteView(ObjectDeleteView):
class ConsolePortBulkImportView(BulkImportView): class ConsolePortBulkImportView(BulkImportView):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
model_form = forms.ConsolePortCSVForm model_form = forms.ConsolePortCSVForm
table = tables.ConsolePortImportTable table = tables.ConsolePortTable
default_return_url = 'dcim:consoleport_list' default_return_url = 'dcim:consoleport_list'
@ -1207,13 +1211,17 @@ class ConsolePortBulkDeleteView(BulkDeleteView):
# #
class ConsoleServerPortListView(ObjectListView): class ConsoleServerPortListView(ObjectListView):
queryset = ConsoleServerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = ConsoleServerPort.objects.prefetch_related('device', 'cable')
filterset = filters.ConsoleServerPortFilterSet filterset = filters.ConsoleServerPortFilterSet
filterset_form = forms.ConsoleServerPortFilterForm filterset_form = forms.ConsoleServerPortFilterForm
table = tables.ConsoleServerPortDetailTable table = tables.ConsoleServerPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class ConsoleServerPortView(ObjectView):
queryset = ConsoleServerPort.objects.all()
class ConsoleServerPortCreateView(ComponentCreateView): class ConsoleServerPortCreateView(ComponentCreateView):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
form = forms.ConsoleServerPortCreateForm form = forms.ConsoleServerPortCreateForm
@ -1233,7 +1241,7 @@ class ConsoleServerPortDeleteView(ObjectDeleteView):
class ConsoleServerPortBulkImportView(BulkImportView): class ConsoleServerPortBulkImportView(BulkImportView):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
model_form = forms.ConsoleServerPortCSVForm model_form = forms.ConsoleServerPortCSVForm
table = tables.ConsoleServerPortImportTable table = tables.ConsoleServerPortTable
default_return_url = 'dcim:consoleserverport_list' default_return_url = 'dcim:consoleserverport_list'
@ -1266,13 +1274,17 @@ class ConsoleServerPortBulkDeleteView(BulkDeleteView):
# #
class PowerPortListView(ObjectListView): class PowerPortListView(ObjectListView):
queryset = PowerPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = PowerPort.objects.prefetch_related('device', 'cable')
filterset = filters.PowerPortFilterSet filterset = filters.PowerPortFilterSet
filterset_form = forms.PowerPortFilterForm filterset_form = forms.PowerPortFilterForm
table = tables.PowerPortDetailTable table = tables.PowerPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class PowerPortView(ObjectView):
queryset = PowerPort.objects.all()
class PowerPortCreateView(ComponentCreateView): class PowerPortCreateView(ComponentCreateView):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
form = forms.PowerPortCreateForm form = forms.PowerPortCreateForm
@ -1292,7 +1304,7 @@ class PowerPortDeleteView(ObjectDeleteView):
class PowerPortBulkImportView(BulkImportView): class PowerPortBulkImportView(BulkImportView):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
model_form = forms.PowerPortCSVForm model_form = forms.PowerPortCSVForm
table = tables.PowerPortImportTable table = tables.PowerPortTable
default_return_url = 'dcim:powerport_list' default_return_url = 'dcim:powerport_list'
@ -1315,13 +1327,17 @@ class PowerPortBulkDeleteView(BulkDeleteView):
# #
class PowerOutletListView(ObjectListView): class PowerOutletListView(ObjectListView):
queryset = PowerOutlet.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = PowerOutlet.objects.prefetch_related('device', 'cable')
filterset = filters.PowerOutletFilterSet filterset = filters.PowerOutletFilterSet
filterset_form = forms.PowerOutletFilterForm filterset_form = forms.PowerOutletFilterForm
table = tables.PowerOutletDetailTable table = tables.PowerOutletTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class PowerOutletView(ObjectView):
queryset = PowerOutlet.objects.all()
class PowerOutletCreateView(ComponentCreateView): class PowerOutletCreateView(ComponentCreateView):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
form = forms.PowerOutletCreateForm form = forms.PowerOutletCreateForm
@ -1341,7 +1357,7 @@ class PowerOutletDeleteView(ObjectDeleteView):
class PowerOutletBulkImportView(BulkImportView): class PowerOutletBulkImportView(BulkImportView):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
model_form = forms.PowerOutletCSVForm model_form = forms.PowerOutletCSVForm
table = tables.PowerOutletImportTable table = tables.PowerOutletTable
default_return_url = 'dcim:poweroutlet_list' default_return_url = 'dcim:poweroutlet_list'
@ -1374,10 +1390,10 @@ class PowerOutletBulkDeleteView(BulkDeleteView):
# #
class InterfaceListView(ObjectListView): class InterfaceListView(ObjectListView):
queryset = Interface.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = Interface.objects.prefetch_related('device', 'cable')
filterset = filters.InterfaceFilterSet filterset = filters.InterfaceFilterSet
filterset_form = forms.InterfaceFilterForm filterset_form = forms.InterfaceFilterForm
table = tables.InterfaceDetailTable table = tables.InterfaceTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1409,7 +1425,7 @@ class InterfaceView(ObjectView):
) )
return render(request, 'dcim/interface.html', { return render(request, 'dcim/interface.html', {
'interface': interface, 'instance': interface,
'connected_interface': interface._connected_interface, 'connected_interface': interface._connected_interface,
'connected_circuittermination': interface._connected_circuittermination, 'connected_circuittermination': interface._connected_circuittermination,
'ipaddress_table': ipaddress_table, 'ipaddress_table': ipaddress_table,
@ -1437,7 +1453,7 @@ class InterfaceDeleteView(ObjectDeleteView):
class InterfaceBulkImportView(BulkImportView): class InterfaceBulkImportView(BulkImportView):
queryset = Interface.objects.all() queryset = Interface.objects.all()
model_form = forms.InterfaceCSVForm model_form = forms.InterfaceCSVForm
table = tables.InterfaceImportTable table = tables.InterfaceTable
default_return_url = 'dcim:interface_list' default_return_url = 'dcim:interface_list'
@ -1470,13 +1486,17 @@ class InterfaceBulkDeleteView(BulkDeleteView):
# #
class FrontPortListView(ObjectListView): class FrontPortListView(ObjectListView):
queryset = FrontPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = FrontPort.objects.prefetch_related('device', 'cable')
filterset = filters.FrontPortFilterSet filterset = filters.FrontPortFilterSet
filterset_form = forms.FrontPortFilterForm filterset_form = forms.FrontPortFilterForm
table = tables.FrontPortDetailTable table = tables.FrontPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class FrontPortView(ObjectView):
queryset = FrontPort.objects.all()
class FrontPortCreateView(ComponentCreateView): class FrontPortCreateView(ComponentCreateView):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
form = forms.FrontPortCreateForm form = forms.FrontPortCreateForm
@ -1496,7 +1516,7 @@ class FrontPortDeleteView(ObjectDeleteView):
class FrontPortBulkImportView(BulkImportView): class FrontPortBulkImportView(BulkImportView):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
model_form = forms.FrontPortCSVForm model_form = forms.FrontPortCSVForm
table = tables.FrontPortImportTable table = tables.FrontPortTable
default_return_url = 'dcim:frontport_list' default_return_url = 'dcim:frontport_list'
@ -1529,13 +1549,17 @@ class FrontPortBulkDeleteView(BulkDeleteView):
# #
class RearPortListView(ObjectListView): class RearPortListView(ObjectListView):
queryset = RearPort.objects.prefetch_related('device', 'device__tenant', 'device__site', 'cable') queryset = RearPort.objects.prefetch_related('device', 'cable')
filterset = filters.RearPortFilterSet filterset = filters.RearPortFilterSet
filterset_form = forms.RearPortFilterForm filterset_form = forms.RearPortFilterForm
table = tables.RearPortDetailTable table = tables.RearPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class RearPortView(ObjectView):
queryset = RearPort.objects.all()
class RearPortCreateView(ComponentCreateView): class RearPortCreateView(ComponentCreateView):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
form = forms.RearPortCreateForm form = forms.RearPortCreateForm
@ -1555,7 +1579,7 @@ class RearPortDeleteView(ObjectDeleteView):
class RearPortBulkImportView(BulkImportView): class RearPortBulkImportView(BulkImportView):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
model_form = forms.RearPortCSVForm model_form = forms.RearPortCSVForm
table = tables.RearPortImportTable table = tables.RearPortTable
default_return_url = 'dcim:rearport_list' default_return_url = 'dcim:rearport_list'
@ -1588,15 +1612,17 @@ class RearPortBulkDeleteView(BulkDeleteView):
# #
class DeviceBayListView(ObjectListView): class DeviceBayListView(ObjectListView):
queryset = DeviceBay.objects.prefetch_related( queryset = DeviceBay.objects.prefetch_related('device', 'installed_device')
'device', 'device__site', 'installed_device', 'installed_device__site'
)
filterset = filters.DeviceBayFilterSet filterset = filters.DeviceBayFilterSet
filterset_form = forms.DeviceBayFilterForm filterset_form = forms.DeviceBayFilterForm
table = tables.DeviceBayDetailTable table = tables.DeviceBayTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
class DeviceBayView(ObjectView):
queryset = DeviceBay.objects.all()
class DeviceBayCreateView(ComponentCreateView): class DeviceBayCreateView(ComponentCreateView):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
form = forms.DeviceBayCreateForm form = forms.DeviceBayCreateForm
@ -1683,7 +1709,7 @@ class DeviceBayDepopulateView(ObjectEditView):
class DeviceBayBulkImportView(BulkImportView): class DeviceBayBulkImportView(BulkImportView):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
model_form = forms.DeviceBayCSVForm model_form = forms.DeviceBayCSVForm
table = tables.DeviceBayImportTable table = tables.DeviceBayTable
default_return_url = 'dcim:devicebay_list' default_return_url = 'dcim:devicebay_list'

View File

@ -296,6 +296,7 @@ class ObjectChangeLogView(View):
return render(request, 'extras/object_changelog.html', { return render(request, 'extras/object_changelog.html', {
object_var: obj, object_var: obj,
'instance': obj, # We'll eventually standardize on 'instance` for the object variable name
'table': objectchanges_table, 'table': objectchanges_table,
'base_template': base_template, 'base_template': base_template,
'active_tab': 'changelog', 'active_tab': 'changelog',

View File

@ -0,0 +1,103 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Console Port</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
{% if instance.connected_endpoint %}
<tr>
<td>Device</td>
<td>
<a href="{{ instance.connected_endpoint.device.get_absolute_url }}">{{ instance.connected_endpoint.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>
<a href="{{ instance.connected_endpoint.get_absolute_url }}">{{ instance.connected_endpoint.name }}</a>
</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.connected_endpoint.get_type_display|placeholder }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.connected_endpoint.description|placeholder }}</td>
</tr>
{% endif %}
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:consoleport_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.connection_status %}
<span class="label label-success">{{ instance.get_connection_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.get_connection_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,103 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Console Server Port</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
{% if instance.connected_endpoint %}
<tr>
<td>Device</td>
<td>
<a href="{{ instance.connected_endpoint.device.get_absolute_url }}">{{ instance.connected_endpoint.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>
<a href="{{ instance.connected_endpoint.get_absolute_url }}">{{ instance.connected_endpoint.name }}</a>
</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.connected_endpoint.get_type_display|placeholder }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.connected_endpoint.description|placeholder }}</td>
</tr>
{% endif %}
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:consoleserverport_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.connection_status %}
<span class="label label-success">{{ instance.get_connection_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.get_connection_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,41 @@
{% extends 'base.html' %}
{% load helpers %}
{% load perms %}
{% load plugins %}
{% block header %}
<div class="row noprint">
<div class="col-md-12">
<ol class="breadcrumb">
<li><a href="{% url 'dcim:device_list' %}">Devices</a></li>
<li><a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a></li>
<li><a href="{% url instance|url_name:"list" %}?device_id={{ instance.device.pk }}">{{ instance|meta:"verbose_name_plural"|bettertitle }}</a></li>
<li>{{ instance }}</li>
</ol>
</div>
</div>
<div class="pull-right noprint">
{% plugin_buttons instance %}
{% if request.user|can_change:instance %}
<a href="{% url instance|url_name:"edit" pk=instance.pk %}" class="btn btn-warning">
<span class="fa fa-pencil" aria-hidden="true"></span> Edit
</a>
{% endif %}
{% if request.user|can_delete:instance %}
<a href="{% url instance|url_name:"delete" pk=instance.pk %}" class="btn btn-danger">
<span class="fa fa-trash" aria-hidden="true"></span> Delete
</a>
{% endif %}
</div>
<h1>{% block title %}{{ instance.device }} / {{ instance }}{% endblock %}</h1>
<ul class="nav nav-tabs">
<li role="presentation"{% if not active_tab %} class="active"{% endif %}>
<a href="{{ instance.get_absolute_url }}">{{ instance|meta:"verbose_name"|bettertitle }}</a>
</li>
{% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
<a href="{% url instance|url_name:"changelog" pk=instance.pk %}">Change Log</a>
</li>
{% endif %}
</ul>
{% endblock %}

View File

@ -0,0 +1,70 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Device Bay</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Installed Device</strong>
</div>
{% if instance.installed_device %}
{% with device=instance.installed_device %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ device.get_absolute_url }}">{{ device }}</a>
</td>
</tr>
<tr>
<td>Device Type</td>
<td>{{ device.device_type }}</td>
</tr>
</table>
{% endwith %}
{% else %}
<div class="panel-body text-muted">
None
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,91 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Front Port</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Rear Port</td>
<td>
<a href="{{ instance.rear_port.get_absolute_url }}">{{ instance.rear_port }}</a>
</td>
</tr>
<tr>
<td>Rear Port Position</td>
<td>{{ instance.rear_port_position }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:frontport_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.cable.status %}
<span class="label label-success">{{ instance.cable.get_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.cable.get_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -2,7 +2,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-keyboard-o"></i> {{ cp }} <i class="fa fa-fw fa-keyboard-o"></i>
<a href="{{ cp.get_absolute_url }}">{{ cp }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -11,7 +11,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-keyboard-o"></i> {{ csp }} <i class="fa fa-fw fa-keyboard-o"></i>
<a href="{{ csp.get_absolute_url }}">{{ csp }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -9,7 +9,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-{% if devicebay.installed_device %}dot-circle-o{% else %}circle-o{% endif %}"></i> {{ devicebay.name }} <i class="fa fa-fw fa-{% if devicebay.installed_device %}dot-circle-o{% else %}circle-o{% endif %}"></i>
<a href="{{ devicebay.get_absolute_url }}">{{ devicebay.name }}</a>
</td> </td>
{# Status #} {# Status #}

View File

@ -10,7 +10,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-square{% if not frontport.cable %}-o{% endif %}"></i> {{ frontport }} <i class="fa fa-fw fa-square{% if not frontport.cable %}-o{% endif %}"></i>
<a href="{{ frontport.get_absolute_url }}">{{ frontport }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -11,7 +11,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-bolt"></i> {{ po }} <i class="fa fa-fw fa-bolt"></i>
<a href="{{ po.get_absolute_url }}">{{ po }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -2,7 +2,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-bolt"></i> {{ pp }} <i class="fa fa-fw fa-bolt"></i>
<a href="{{ pp.get_absolute_url }}">{{ pp }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -10,7 +10,8 @@
{# Name #} {# Name #}
<td> <td>
<i class="fa fa-fw fa-square{% if not rearport.cable %}-o{% endif %}"></i> {{ rearport }} <i class="fa fa-fw fa-square{% if not rearport.cable %}-o{% endif %}"></i>
<a href="{{ rearport.get_absolute_url }}">{{ rearport }}</a>
</td> </td>
{# Type #} {# Type #}

View File

@ -1,40 +1,6 @@
{% extends 'base.html' %} {% extends 'dcim/device_component.html' %}
{% load helpers %} {% load helpers %}
{% load plugins %}
{% block header %}
<div class="row noprint">
<div class="col-md-12">
<ol class="breadcrumb">
<li><a href="{% url 'dcim:device_list' %}">Devices</a></li>
<li><a href="{{ interface.device.get_absolute_url }}">{{ interface.device }}</a></li>
<li>{{ interface }}</li>
</ol>
</div>
</div>
<div class="pull-right noprint">
{% if perms.dcim.change_interface %}
<a href="{% url 'dcim:interface_edit' pk=interface.pk %}" class="btn btn-warning">
<span class="fa fa-pencil" aria-hidden="true"></span> Edit
</a>
{% endif %}
{% if perms.dcim.delete_interface %}
<a href="{% url 'dcim:interface_delete' pk=interface.pk %}" class="btn btn-danger">
<span class="fa fa-trash" aria-hidden="true"></span> Delete
</a>
{% endif %}
</div>
<h1>{% block title %}{{ interface.device }} / {{ interface.name }}{% endblock %}</h1>
<ul class="nav nav-tabs">
<li role="presentation"{% if not active_tab %} class="active"{% endif %}>
<a href="{{ interface.get_absolute_url }}">Interface</a>
</li>
{% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
<a href="{% url 'dcim:interface_changelog' pk=interface.pk %}">Change Log</a>
</li>
{% endif %}
</ul>
{% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
@ -47,25 +13,25 @@
<tr> <tr>
<td>Device</td> <td>Device</td>
<td> <td>
<a href="{{ interface.device.get_absolute_url }}">{{ interface.device }}</a> <a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Name</td> <td>Name</td>
<td>{{ interface.name }}</td> <td>{{ instance.name }}</td>
</tr> </tr>
<tr> <tr>
<td>Label</td> <td>Label</td>
<td>{{ interface.label|placeholder }}</td> <td>{{ instance.label|placeholder }}</td>
</tr> </tr>
<tr> <tr>
<td>Type</td> <td>Type</td>
<td>{{ interface.get_type_display }}</td> <td>{{ instance.get_type_display }}</td>
</tr> </tr>
<tr> <tr>
<td>Enabled</td> <td>Enabled</td>
<td> <td>
{% if interface.enabled %} {% if instance.enabled %}
<span class="text-success"><i class="fa fa-check"></i></span> <span class="text-success"><i class="fa fa-check"></i></span>
{% else %} {% else %}
<span class="text-danger"><i class="fa fa-close"></i></span> <span class="text-danger"><i class="fa fa-close"></i></span>
@ -75,8 +41,8 @@
<tr> <tr>
<td>LAG</td> <td>LAG</td>
<td> <td>
{% if interface.lag%} {% if instance.lag%}
<a href="{{ interface.lag.get_absolute_url }}">{{ interface.lag }}</a> <a href="{{ instance.lag.get_absolute_url }}">{{ instance.lag }}</a>
{% else %} {% else %}
<span class="text-muted">None</span> <span class="text-muted">None</span>
{% endif %} {% endif %}
@ -84,31 +50,32 @@
</tr> </tr>
<tr> <tr>
<td>Description</td> <td>Description</td>
<td>{{ interface.description|placeholder }} </td> <td>{{ instance.description|placeholder }} </td>
</tr> </tr>
<tr> <tr>
<td>MTU</td> <td>MTU</td>
<td>{{ interface.mtu|placeholder }}</td> <td>{{ instance.mtu|placeholder }}</td>
</tr> </tr>
<tr> <tr>
<td>MAC Address</td> <td>MAC Address</td>
<td><span class="text-monospace">{{ interface.mac_address|placeholder }}</span></td> <td><span class="text-monospace">{{ instance.mac_address|placeholder }}</span></td>
</tr> </tr>
<tr> <tr>
<td>802.1Q Mode</td> <td>802.1Q Mode</td>
<td>{{ interface.get_mode_display }}</td> <td>{{ instance.get_mode_display }}</td>
</tr> </tr>
</table> </table>
</div> </div>
{% include 'extras/inc/tags_panel.html' with tags=interface.tags.all %} {% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% if interface.is_connectable %} {% if instance.is_connectable %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<strong>Connection</strong> <strong>Connection</strong>
</div> </div>
{% if interface.cable %} {% if instance.cable %}
<table class="table table-hover panel-body attr-table"> <table class="table table-hover panel-body attr-table">
{% if connected_interface %} {% if connected_interface %}
<tr> <tr>
@ -182,8 +149,8 @@
<tr> <tr>
<td>Cable</td> <td>Cable</td>
<td> <td>
<a href="{{ interface.cable.get_absolute_url }}">{{ interface.cable }}</a> <a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:interface_trace' pk=interface.pk %}" class="btn btn-primary btn-xs" title="Trace"> <a href="{% url 'dcim:interface_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i> <i class="fa fa-share-alt" aria-hidden="true"></i>
</a> </a>
</td> </td>
@ -191,10 +158,10 @@
<tr> <tr>
<td>Connection Status</td> <td>Connection Status</td>
<td> <td>
{% if interface.connection_status %} {% if instance.connection_status %}
<span class="label label-success">{{ interface.get_connection_status_display }}</span> <span class="label label-success">{{ instance.get_connection_status_display }}</span>
{% else %} {% else %}
<span class="label label-info">{{ interface.get_connection_status_display }}</span> <span class="label label-info">{{ instance.get_connection_status_display }}</span>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@ -206,7 +173,7 @@
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
{% if interface.is_lag %} {% if instance.is_lag %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>LAG Members</strong></div> <div class="panel-heading"><strong>LAG Members</strong></div>
<table class="table table-hover table-headings panel-body"> <table class="table table-hover table-headings panel-body">
@ -218,7 +185,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for member in interface.member_interfaces.all %} {% for member in instance.member_interfaces.all %}
<tr> <tr>
<td> <td>
<a href="{{ member.device.get_absolute_url }}">{{ member.device }}</a> <a href="{{ member.device.get_absolute_url }}">{{ member.device }}</a>
@ -239,6 +206,7 @@
</table> </table>
</div> </div>
{% endif %} {% endif %}
{% plugin_right_page instance %}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -251,4 +219,9 @@
{% include 'panel_table.html' with table=vlan_table heading="VLANs" %} {% include 'panel_table.html' with table=vlan_table heading="VLANs" %}
</div> </div>
</div> </div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,111 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Power Outlet</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
<tr>
<td>Power Port</td>
<td>{{ instance.power_port }}</td>
</tr>
<tr>
<td>Feed Leg</td>
<td>{{ instance.get_feed_leg_display }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
{% if instance.connected_endpoint %}
<tr>
<td>Device</td>
<td>
<a href="{{ instance.connected_endpoint.device.get_absolute_url }}">{{ instance.connected_endpoint.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>
<a href="{{ instance.connected_endpoint.get_absolute_url }}">{{ instance.connected_endpoint.name }}</a>
</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.connected_endpoint.get_type_display|placeholder }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.connected_endpoint.description|placeholder }}</td>
</tr>
{% endif %}
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:poweroutlet_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.connection_status %}
<span class="label label-success">{{ instance.get_connection_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.get_connection_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,111 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Power Port</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
<tr>
<td>Maximum Draw</td>
<td>{{ instance.maximum_draw|placeholder }}</td>
</tr>
<tr>
<td>Allocated Draw</td>
<td>{{ instance.allocated_draw|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
{% if instance.connected_endpoint %}
<tr>
<td>Device</td>
<td>
<a href="{{ instance.connected_endpoint.device.get_absolute_url }}">{{ instance.connected_endpoint.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>
<a href="{{ instance.connected_endpoint.get_absolute_url }}">{{ instance.connected_endpoint.name }}</a>
</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.connected_endpoint.get_type_display|placeholder }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.connected_endpoint.description|placeholder }}</td>
</tr>
{% endif %}
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:powerport_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.connection_status %}
<span class="label label-success">{{ instance.get_connection_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.get_connection_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,85 @@
{% extends 'dcim/device_component.html' %}
{% load helpers %}
{% load plugins %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Rear Port</strong>
</div>
<table class="table table-hover panel-body attr-table">
<tr>
<td>Device</td>
<td>
<a href="{{ instance.device.get_absolute_url }}">{{ instance.device }}</a>
</td>
</tr>
<tr>
<td>Name</td>
<td>{{ instance.name }}</td>
</tr>
<tr>
<td>Label</td>
<td>{{ instance.label|placeholder }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ instance.get_type_display }}</td>
</tr>
<tr>
<td>Positions</td>
<td>{{ instance.positions }}</td>
</tr>
<tr>
<td>Description</td>
<td>{{ instance.description|placeholder }}</td>
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=instance.tags.all %}
{% plugin_left_page instance %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if instance.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>
<td>
<a href="{{ instance.cable.get_absolute_url }}">{{ instance.cable }}</a>
<a href="{% url 'dcim:rearport_trace' pk=instance.pk %}" class="btn btn-primary btn-xs" title="Trace">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</a>
</td>
</tr>
<tr>
<td>Connection Status</td>
<td>
{% if instance.cable.status %}
<span class="label label-success">{{ instance.cable.get_status_display }}</span>
{% else %}
<span class="label label-info">{{ instance.cable.get_status_display }}</span>
{% endif %}
</td>
</tr>
</table>
{% else %}
<div class="panel-body text-muted">
Not connected
</div>
{% endif %}
</div>
{% plugin_right_page instance %}
</div>
</div>
<div class="row">
<div class="col-md-12">
{% plugin_full_width_page instance %}
</div>
</div>
{% endblock %}

View File

@ -5,7 +5,6 @@ import re
import yaml import yaml
from django import template from django import template
from django.conf import settings from django.conf import settings
from django.urls import NoReverseMatch, reverse
from django.utils.html import strip_tags from django.utils.html import strip_tags
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from markdown import markdown from markdown import markdown
@ -79,14 +78,7 @@ def url_name(model, action):
""" """
Return the URL name for the given model and action, or None if invalid. Return the URL name for the given model and action, or None if invalid.
""" """
url_name = '{}:{}_{}'.format(model._meta.app_label, model._meta.model_name, action) return '{}:{}_{}'.format(model._meta.app_label, model._meta.model_name, action)
try:
# Validate and return the URL name. We don't return the actual URL yet because many of the templates
# are written to pass a name to {% url %}.
reverse(url_name)
return url_name
except NoReverseMatch:
return None
@register.filter() @register.filter()

View File

@ -0,0 +1,30 @@
from django import template
register = template.Library()
def _check_permission(user, instance, action):
return user.has_perm(
perm=f'{instance._meta.app_label}.{action}_{instance._meta.model_name}',
obj=instance
)
@register.filter()
def can_view(user, instance):
return _check_permission(user, instance, 'view')
@register.filter()
def can_add(user, instance):
return _check_permission(user, instance, 'add')
@register.filter()
def can_change(user, instance):
return _check_permission(user, instance, 'change')
@register.filter()
def can_delete(user, instance):
return _check_permission(user, instance, 'delete')

View File

@ -917,6 +917,7 @@ class ViewTestCases:
maxDiff = None maxDiff = None
class DeviceComponentViewTestCase( class DeviceComponentViewTestCase(
GetObjectViewTestCase,
EditObjectViewTestCase, EditObjectViewTestCase,
DeleteObjectViewTestCase, DeleteObjectViewTestCase,
ListObjectsViewTestCase, ListObjectsViewTestCase,

View File

@ -127,6 +127,25 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
def get_required_permission(self): def get_required_permission(self):
return get_permission_for_model(self.queryset.model, 'view') return get_permission_for_model(self.queryset.model, 'view')
def get_template_name(self):
"""
Return self.template_name if set. Otherwise, resolve the template path by model app_label and name.
"""
if hasattr(self, 'template_name'):
return self.template_name
model_opts = self.queryset.model._meta
return f'{model_opts.app_label}/{model_opts.model_name}.html'
def get(self, request, pk):
"""
Generic GET handler for accessing an object by PK
"""
instance = get_object_or_404(self.queryset, pk=pk)
return render(request, self.get_template_name(), {
'instance': instance,
})
class ObjectListView(ObjectPermissionRequiredMixin, View): class ObjectListView(ObjectPermissionRequiredMixin, View):
""" """

View File

@ -189,10 +189,7 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
} }
class VMInterfaceTestCase( class VMInterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
ViewTestCases.GetObjectViewTestCase,
ViewTestCases.DeviceComponentViewTestCase,
):
model = VMInterface model = VMInterface
@classmethod @classmethod