Coverage for dcim/ui/panels.py: 92%
434 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.contrib.contenttypes.models import ContentType
2from django.utils.translation import gettext_lazy as _
4from netbox.ui import actions, attrs, panels
7class BayTypeIncompatibilityPanel(panels.Panel):
8 """
9 Renders a warning banner when a Module is incompatibly installed (its type's bay type set and
10 the bay's bay type set are both non-empty and share no common members).
11 Silently omitted when the installation is compatible or unconstrained.
12 """
13 template_name = 'dcim/panels/bay_type_incompatibility.html'
15 def should_render(self, context):
16 from dcim.models import Module, ModuleBay
17 obj = context.get('object')
18 if isinstance(obj, Module):
19 return not obj.is_bay_compatible
20 if isinstance(obj, ModuleBay):
21 return not obj.is_module_compatible
22 return False
24 def get_context(self, context):
25 from dcim.models import Module
26 ctx = super().get_context(context)
27 ctx['is_module_view'] = isinstance(context.get('object'), Module)
28 return ctx
31class SitePanel(panels.ObjectAttributesPanel):
32 region = attrs.NestedObjectAttr('region', linkify=True)
33 group = attrs.NestedObjectAttr('group', linkify=True)
34 name = attrs.TextAttr('name')
35 status = attrs.ChoiceAttr('status')
36 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
37 facility = attrs.TextAttr('facility')
38 description = attrs.TextAttr('description')
39 timezone = attrs.TimezoneAttr('time_zone')
40 physical_address = attrs.AddressAttr('physical_address', map_url=True)
41 shipping_address = attrs.AddressAttr('shipping_address', map_url=True)
42 gps_coordinates = attrs.GPSCoordinatesAttr()
45class LocationPanel(panels.NestedGroupObjectPanel):
46 site = attrs.RelatedObjectAttr('site', linkify=True, grouped_by='group')
47 status = attrs.ChoiceAttr('status')
48 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
49 facility = attrs.TextAttr('facility')
52class RackDimensionsPanel(panels.ObjectAttributesPanel):
53 form_factor = attrs.ChoiceAttr('form_factor')
54 width = attrs.ChoiceAttr('width')
55 height = attrs.TextAttr('u_height', format_string='{}U', label=_('Height'))
56 outer_width = attrs.NumericAttr('outer_width', unit_accessor='get_outer_unit_display')
57 outer_height = attrs.NumericAttr('outer_height', unit_accessor='get_outer_unit_display')
58 outer_depth = attrs.NumericAttr('outer_depth', unit_accessor='get_outer_unit_display')
59 mounting_depth = attrs.TextAttr('mounting_depth', format_string=_('{0} millimeters'))
62class RackNumberingPanel(panels.ObjectAttributesPanel):
63 starting_unit = attrs.TextAttr('starting_unit')
64 desc_units = attrs.BooleanAttr('desc_units', label=_('Descending units'))
67class RackPanel(panels.ObjectAttributesPanel):
68 region = attrs.NestedObjectAttr('site.region', linkify=True)
69 site = attrs.RelatedObjectAttr('site', linkify=True, grouped_by='group')
70 location = attrs.NestedObjectAttr('location', linkify=True)
71 group = attrs.RelatedObjectAttr('group', linkify=True, label=_('Rack group'))
72 name = attrs.TextAttr('name')
73 facility_id = attrs.TextAttr('facility_id', label=_('Facility ID'))
74 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
75 status = attrs.ChoiceAttr('status')
76 rack_type = attrs.RelatedObjectAttr('rack_type', linkify=True, grouped_by='manufacturer')
77 role = attrs.RelatedObjectAttr('role', linkify=True, colored=True)
78 description = attrs.TextAttr('description')
79 serial = attrs.TextAttr('serial', label=_('Serial number'), style='font-monospace', copy_button=True)
80 asset_tag = attrs.TextAttr('asset_tag', style='font-monospace', copy_button=True)
81 airflow = attrs.ChoiceAttr('airflow')
82 cooling_capability = attrs.ChoiceAttr('cooling_capability')
83 cooling_capacity = attrs.TextAttr('cooling_capacity', format_string=_('{} kW'))
84 space_utilization = attrs.UtilizationAttr('get_utilization')
85 power_utilization = attrs.UtilizationAttr('get_power_utilization')
88class RackWeightPanel(panels.ObjectAttributesPanel):
89 weight = attrs.WeightAttr('weight')
90 max_weight = attrs.WeightAttr('max_weight', label=_('Maximum weight'))
91 total_weight = attrs.TemplatedAttr('total_weight', template_name='dcim/attrs/total_weight.html')
94class RackRolePanel(panels.OrganizationalObjectPanel):
95 color = attrs.ColorAttr('color')
98class RackReservationPanel(panels.ObjectAttributesPanel):
99 units = attrs.TextAttr('unit_list')
100 unit_count = attrs.TextAttr('unit_count', label=_("Total U's"))
101 status = attrs.ChoiceAttr('status')
102 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
103 user = attrs.RelatedObjectAttr('user', linkify=True)
104 description = attrs.TextAttr('description')
107class RackTypePanel(panels.ObjectAttributesPanel):
108 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
109 model = attrs.TextAttr('model')
110 description = attrs.TextAttr('description')
111 cooling_capability = attrs.ChoiceAttr('cooling_capability')
112 cooling_capacity = attrs.TextAttr('cooling_capacity', format_string=_('{} kW'))
115class DevicePanel(panels.ObjectAttributesPanel):
116 region = attrs.NestedObjectAttr('site.region', linkify=True)
117 site = attrs.RelatedObjectAttr('site', linkify=True, grouped_by='group')
118 location = attrs.NestedObjectAttr('location', linkify=True)
119 rack = attrs.TemplatedAttr('rack', template_name='dcim/device/attrs/rack.html')
120 virtual_chassis = attrs.RelatedObjectAttr('virtual_chassis', linkify=True)
121 parent_device = attrs.TemplatedAttr('parent_bay', template_name='dcim/device/attrs/parent_device.html')
122 gps_coordinates = attrs.GPSCoordinatesAttr()
123 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
124 description = attrs.TextAttr('description')
125 cooling_method = attrs.ChoiceAttr('cooling_method')
126 airflow = attrs.ChoiceAttr('airflow')
127 serial = attrs.TextAttr('serial', label=_('Serial number'), style='font-monospace', copy_button=True)
128 asset_tag = attrs.TextAttr('asset_tag', style='font-monospace', copy_button=True)
129 config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
132class DeviceManagementPanel(panels.ObjectAttributesPanel):
133 title = _('Management')
135 status = attrs.ChoiceAttr('status')
136 role = attrs.NestedObjectAttr('role', linkify=True, max_depth=3, colored=True)
137 platform = attrs.NestedObjectAttr('platform', linkify=True, max_depth=3)
138 primary_ip4 = attrs.TemplatedAttr(
139 'primary_ip4',
140 label=_('Primary IPv4'),
141 template_name='dcim/device/attrs/ipaddress.html',
142 )
143 primary_ip6 = attrs.TemplatedAttr(
144 'primary_ip6',
145 label=_('Primary IPv6'),
146 template_name='dcim/device/attrs/ipaddress.html',
147 )
148 oob_ip = attrs.TemplatedAttr(
149 'oob_ip',
150 label=_('Out-of-band IP'),
151 template_name='dcim/device/attrs/ipaddress.html',
152 )
153 cluster = attrs.RelatedObjectAttr('cluster', linkify=True)
156class DeviceDeviceTypePanel(panels.ObjectAttributesPanel):
157 title = _('Device Type')
159 manufacturer = attrs.RelatedObjectAttr('device_type.manufacturer', linkify=True)
160 model = attrs.RelatedObjectAttr('device_type', linkify=True)
161 height = attrs.TemplatedAttr('device_type.u_height', template_name='dcim/devicetype/attrs/height.html')
162 front_image = attrs.ImageAttr('device_type.front_image')
163 rear_image = attrs.ImageAttr('device_type.rear_image')
166class DeviceDimensionsPanel(panels.ObjectAttributesPanel):
167 title = _('Dimensions')
169 total_weight = attrs.TemplatedAttr('total_weight', template_name='dcim/attrs/total_weight.html')
172class DeviceRolePanel(panels.NestedGroupObjectPanel):
173 color = attrs.ColorAttr('color')
174 vm_role = attrs.BooleanAttr('vm_role', label=_('VM role'))
175 config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
178class DeviceTypePanel(panels.ObjectAttributesPanel):
179 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
180 model = attrs.TextAttr('model')
181 part_number = attrs.TextAttr('part_number')
182 default_platform = attrs.NestedObjectAttr('default_platform', linkify=True, max_depth=3)
183 description = attrs.TextAttr('description')
184 height = attrs.TemplatedAttr('u_height', template_name='dcim/devicetype/attrs/height.html')
185 exclude_from_utilization = attrs.BooleanAttr('exclude_from_utilization')
186 full_depth = attrs.BooleanAttr('is_full_depth')
187 weight = attrs.WeightAttr('weight')
188 subdevice_role = attrs.ChoiceAttr('subdevice_role', label=_('Parent/child'))
189 cooling_method = attrs.ChoiceAttr('cooling_method')
190 airflow = attrs.ChoiceAttr('airflow')
191 end_of_life = attrs.DateTimeAttr('end_of_life', spec='date')
192 front_image = attrs.ImageAttr('front_image')
193 rear_image = attrs.ImageAttr('rear_image')
196class ModulePanel(panels.ObjectAttributesPanel):
197 device = attrs.RelatedObjectAttr('device', linkify=True)
198 device_type = attrs.RelatedObjectAttr('device.device_type', linkify=True, grouped_by='manufacturer')
199 module_bay = attrs.NestedObjectAttr('module_bay', linkify=True)
200 status = attrs.ChoiceAttr('status')
201 description = attrs.TextAttr('description')
202 serial = attrs.TextAttr('serial', label=_('Serial number'), style='font-monospace', copy_button=True)
203 asset_tag = attrs.TextAttr('asset_tag', style='font-monospace', copy_button=True)
206class ModuleBayTypePanel(panels.ObjectAttributesPanel):
207 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
208 name = attrs.TextAttr('name')
209 color = attrs.ColorAttr('color')
210 description = attrs.TextAttr('description')
213class ModuleTypeProfilePanel(panels.ObjectAttributesPanel):
214 name = attrs.TextAttr('name')
215 description = attrs.TextAttr('description')
218class ModuleTypePanel(panels.ObjectAttributesPanel):
219 profile = attrs.RelatedObjectAttr('profile', linkify=True)
220 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
221 model = attrs.TextAttr('model', label=_('Model name'))
222 part_number = attrs.TextAttr('part_number')
223 description = attrs.TextAttr('description')
224 cooling_method = attrs.ChoiceAttr('cooling_method')
225 airflow = attrs.ChoiceAttr('airflow')
226 weight = attrs.WeightAttr('weight')
227 end_of_life = attrs.DateTimeAttr('end_of_life', spec='date')
228 module_bay_types = attrs.RelatedObjectListAttr(
229 'module_bay_types', label=_('Bay Type Compatibility'), linkify=True
230 )
233class PlatformPanel(panels.NestedGroupObjectPanel):
234 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
235 config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
238class ConsolePortPanel(panels.ObjectAttributesPanel):
239 device = attrs.RelatedObjectAttr('device', linkify=True)
240 module = attrs.RelatedObjectAttr('module', linkify=True)
241 name = attrs.TextAttr('name')
242 label = attrs.TextAttr('label')
243 type = attrs.ChoiceAttr('type')
244 speed = attrs.ChoiceAttr('speed')
245 description = attrs.TextAttr('description')
248class ConsoleServerPortPanel(panels.ObjectAttributesPanel):
249 device = attrs.RelatedObjectAttr('device', linkify=True)
250 module = attrs.RelatedObjectAttr('module', linkify=True)
251 name = attrs.TextAttr('name')
252 label = attrs.TextAttr('label')
253 type = attrs.ChoiceAttr('type')
254 speed = attrs.ChoiceAttr('speed')
255 description = attrs.TextAttr('description')
258class PowerPortPanel(panels.ObjectAttributesPanel):
259 device = attrs.RelatedObjectAttr('device', linkify=True)
260 module = attrs.RelatedObjectAttr('module', linkify=True)
261 name = attrs.TextAttr('name')
262 label = attrs.TextAttr('label')
263 type = attrs.ChoiceAttr('type')
264 description = attrs.TextAttr('description')
265 maximum_draw = attrs.TextAttr('maximum_draw', format_string='{}W')
266 allocated_draw = attrs.TextAttr('allocated_draw', format_string='{}W')
269class PowerOutletPanel(panels.ObjectAttributesPanel):
270 device = attrs.RelatedObjectAttr('device', linkify=True)
271 module = attrs.RelatedObjectAttr('module', linkify=True)
272 name = attrs.TextAttr('name')
273 label = attrs.TextAttr('label')
274 type = attrs.ChoiceAttr('type')
275 status = attrs.ChoiceAttr('status')
276 description = attrs.TextAttr('description')
277 color = attrs.ColorAttr('color')
278 power_port = attrs.RelatedObjectAttr('power_port', linkify=True)
279 feed_leg = attrs.ChoiceAttr('feed_leg')
282class CoolingIntakePanel(panels.ObjectAttributesPanel):
283 device = attrs.RelatedObjectAttr('device', linkify=True)
284 module = attrs.RelatedObjectAttr('module', linkify=True)
285 name = attrs.TextAttr('name')
286 label = attrs.TextAttr('label')
287 type = attrs.ChoiceAttr('type')
288 diameter = attrs.DiameterAttr('diameter')
289 max_flow = attrs.FlowRateAttr('max_flow')
290 cooling_outflow = attrs.RelatedObjectAttr('cooling_outflow', linkify=True)
291 description = attrs.TextAttr('description')
294class CoolingOutflowPanel(panels.ObjectAttributesPanel):
295 device = attrs.RelatedObjectAttr('device', linkify=True)
296 module = attrs.RelatedObjectAttr('module', linkify=True)
297 name = attrs.TextAttr('name')
298 label = attrs.TextAttr('label')
299 type = attrs.ChoiceAttr('type')
300 diameter = attrs.DiameterAttr('diameter')
301 cooling_intake = attrs.RelatedObjectAttr('cooling_intake', linkify=True)
302 description = attrs.TextAttr('description')
305class FrontPortPanel(panels.ObjectAttributesPanel):
306 device = attrs.RelatedObjectAttr('device', linkify=True)
307 module = attrs.RelatedObjectAttr('module', linkify=True)
308 name = attrs.TextAttr('name')
309 label = attrs.TextAttr('label')
310 type = attrs.ChoiceAttr('type')
311 color = attrs.ColorAttr('color')
312 positions = attrs.NumericAttr('positions')
313 description = attrs.TextAttr('description')
316class RearPortPanel(panels.ObjectAttributesPanel):
317 device = attrs.RelatedObjectAttr('device', linkify=True)
318 module = attrs.RelatedObjectAttr('module', linkify=True)
319 name = attrs.TextAttr('name')
320 label = attrs.TextAttr('label')
321 type = attrs.ChoiceAttr('type')
322 color = attrs.ColorAttr('color')
323 positions = attrs.NumericAttr('positions')
324 description = attrs.TextAttr('description')
327class ModuleBayPanel(panels.ObjectAttributesPanel):
328 device = attrs.RelatedObjectAttr('device', linkify=True)
329 module = attrs.RelatedObjectAttr('module', linkify=True)
330 name = attrs.TextAttr('name')
331 label = attrs.TextAttr('label')
332 position = attrs.TextAttr('position')
333 description = attrs.TextAttr('description')
334 module_bay_types = attrs.RelatedObjectListAttr('module_bay_types', label=_('Bay Type Compatibility'), linkify=True)
337class InstalledModulePanel(panels.ObjectAttributesPanel):
338 title = _('Installed Module')
339 module = attrs.RelatedObjectAttr('installed_module', linkify=True)
340 manufacturer = attrs.RelatedObjectAttr('installed_module.module_type.manufacturer', linkify=True)
341 module_type = attrs.RelatedObjectAttr('installed_module.module_type', linkify=True)
342 serial = attrs.TextAttr('installed_module.serial', label=_('Serial number'), style='font-monospace')
343 asset_tag = attrs.TextAttr('installed_module.asset_tag', style='font-monospace')
346class DeviceBayPanel(panels.ObjectAttributesPanel):
347 device = attrs.RelatedObjectAttr('device', linkify=True)
348 name = attrs.TextAttr('name')
349 label = attrs.TextAttr('label')
350 description = attrs.TextAttr('description')
353class InstalledDevicePanel(panels.ObjectAttributesPanel):
354 title = _('Installed Device')
355 device = attrs.RelatedObjectAttr('installed_device', linkify=True)
356 device_type = attrs.RelatedObjectAttr('installed_device.device_type')
359class InventoryItemPanel(panels.ObjectAttributesPanel):
360 device = attrs.RelatedObjectAttr('device', linkify=True)
361 parent = attrs.RelatedObjectAttr('parent', linkify=True, label=_('Parent item'))
362 name = attrs.TextAttr('name')
363 label = attrs.TextAttr('label')
364 status = attrs.ChoiceAttr('status')
365 role = attrs.RelatedObjectAttr('role', linkify=True, colored=True)
366 component = attrs.GenericForeignKeyAttr('component', linkify=True)
367 manufacturer = attrs.RelatedObjectAttr('manufacturer', linkify=True)
368 part_id = attrs.TextAttr('part_id', label=_('Part ID'))
369 serial = attrs.TextAttr('serial')
370 asset_tag = attrs.TextAttr('asset_tag')
371 description = attrs.TextAttr('description')
374class InventoryItemRolePanel(panels.OrganizationalObjectPanel):
375 color = attrs.ColorAttr('color')
378class CablePanel(panels.ObjectAttributesPanel):
379 type = attrs.ChoiceAttr('type')
380 status = attrs.ChoiceAttr('status')
381 profile = attrs.ChoiceAttr('profile')
382 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
383 bundle = attrs.RelatedObjectAttr('bundle', linkify=True)
384 label = attrs.TextAttr('label')
385 description = attrs.TextAttr('description')
386 color = attrs.ColorAttr('color')
387 length = attrs.NumericAttr('length', unit_accessor='get_length_unit_display')
390class VirtualChassisPanel(panels.ObjectAttributesPanel):
391 domain = attrs.TextAttr('domain')
392 master = attrs.RelatedObjectAttr('master', linkify=True)
393 description = attrs.TextAttr('description')
396class PowerPanelPanel(panels.ObjectAttributesPanel):
397 site = attrs.RelatedObjectAttr('site', linkify=True)
398 location = attrs.NestedObjectAttr('location', linkify=True)
399 description = attrs.TextAttr('description')
402class PowerFeedPanel(panels.ObjectAttributesPanel):
403 power_panel = attrs.RelatedObjectAttr('power_panel', linkify=True)
404 rack = attrs.RelatedObjectAttr('rack', linkify=True)
405 type = attrs.ChoiceAttr('type')
406 status = attrs.ChoiceAttr('status')
407 description = attrs.TextAttr('description')
408 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
409 connected_device = attrs.TemplatedAttr(
410 'connected_endpoints',
411 label=_('Connected device'),
412 template_name='dcim/powerfeed/attrs/connected_device.html',
413 )
414 utilization = attrs.TemplatedAttr(
415 'connected_endpoints',
416 label=_('Utilization (allocated)'),
417 template_name='dcim/powerfeed/attrs/utilization.html',
418 )
421class PowerFeedElectricalPanel(panels.ObjectAttributesPanel):
422 title = _('Electrical Characteristics')
424 supply = attrs.ChoiceAttr('supply')
425 voltage = attrs.TextAttr('voltage', format_string='{}V')
426 amperage = attrs.TextAttr('amperage', format_string='{}A')
427 phase = attrs.ChoiceAttr('phase')
428 max_utilization = attrs.TextAttr('max_utilization', format_string='{}%')
431class CoolingSourcePanel(panels.ObjectAttributesPanel):
432 site = attrs.RelatedObjectAttr('site', linkify=True)
433 location = attrs.NestedObjectAttr('location', linkify=True)
434 type = attrs.ChoiceAttr('type')
435 status = attrs.ChoiceAttr('status')
436 fluid_type = attrs.ChoiceAttr('fluid_type')
437 cooling_capacity = attrs.TextAttr('cooling_capacity', format_string=_('{} kW'))
438 description = attrs.TextAttr('description')
441class CoolingFeedPanel(panels.ObjectAttributesPanel):
442 cooling_source = attrs.RelatedObjectAttr('cooling_source', linkify=True)
443 rack = attrs.RelatedObjectAttr('rack', linkify=True)
444 status = attrs.ChoiceAttr('status')
445 description = attrs.TextAttr('description')
446 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
449class CoolingFeedCharacteristicsPanel(panels.ObjectAttributesPanel):
450 title = _('Cooling Characteristics')
452 cooling_capacity = attrs.TextAttr('cooling_capacity', format_string=_('{} kW'))
453 max_flow = attrs.FlowRateAttr('max_flow')
456class VirtualDeviceContextPanel(panels.ObjectAttributesPanel):
457 name = attrs.TextAttr('name')
458 device = attrs.RelatedObjectAttr('device', linkify=True)
459 identifier = attrs.TextAttr('identifier')
460 status = attrs.ChoiceAttr('status')
461 primary_ip4 = attrs.TemplatedAttr(
462 'primary_ip4',
463 label=_('Primary IPv4'),
464 template_name='dcim/device/attrs/ipaddress.html',
465 )
466 primary_ip6 = attrs.TemplatedAttr(
467 'primary_ip6',
468 label=_('Primary IPv6'),
469 template_name='dcim/device/attrs/ipaddress.html',
470 )
471 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
474class MACAddressPanel(panels.ObjectAttributesPanel):
475 mac_address = attrs.TextAttr('mac_address', label=_('MAC address'), style='font-monospace', copy_button=True)
476 description = attrs.TextAttr('description')
477 assignment = attrs.RelatedObjectAttr('assigned_object', linkify=True, grouped_by='parent_object')
478 is_primary = attrs.BooleanAttr('is_primary', label=_('Primary for interface'))
481class ConnectionPanel(panels.ObjectPanel):
482 """
483 A panel which displays connection information for a cabled object.
484 """
485 template_name = 'dcim/panels/connection.html'
486 title = _('Connection')
488 def __init__(self, trace_url_name, connect_options=None, show_endpoints=True, **kwargs):
489 super().__init__(**kwargs)
490 self.trace_url_name = trace_url_name
491 self.connect_options = connect_options or []
492 self.show_endpoints = show_endpoints
494 def get_context(self, context):
495 return {
496 **super().get_context(context),
497 'trace_url_name': self.trace_url_name,
498 'connect_options': self.connect_options,
499 'show_endpoints': self.show_endpoints,
500 }
503class InventoryItemsPanel(panels.ObjectPanel):
504 """
505 A panel which displays inventory items associated with a component.
506 """
507 template_name = 'dcim/panels/component_inventory_items.html'
508 title = _('Inventory Items')
509 actions = [
510 actions.AddObject(
511 'dcim.inventoryitem',
512 url_params={
513 'component_type': lambda ctx: ContentType.objects.get_for_model(ctx['object']).pk,
514 'component_id': lambda ctx: ctx['object'].pk,
515 },
516 ),
517 ]
520class VirtualChassisMembersPanel(panels.ObjectPanel):
521 """
522 A panel which lists all members of a virtual chassis.
523 """
525 template_name = 'dcim/panels/virtual_chassis_members.html'
526 title = _('Virtual Chassis Members')
527 actions = [
528 actions.AddObject(
529 'dcim.device',
530 url_params={
531 'site': lambda ctx: (
532 ctx['virtual_chassis'].master.site_id
533 if ctx['virtual_chassis'] and ctx['virtual_chassis'].master_id
534 else ''
535 ),
536 'rack': lambda ctx: (
537 ctx['virtual_chassis'].master.rack_id
538 if ctx['virtual_chassis'] and ctx['virtual_chassis'].master_id
539 else ''
540 ),
541 },
542 ),
543 ]
545 def get_context(self, context):
546 return {
547 **super().get_context(context),
548 'virtual_chassis': context.get('virtual_chassis'),
549 'vc_members': context.get('vc_members'),
550 }
552 def should_render(self, context):
553 return bool(context.get('vc_members'))
556class PowerUtilizationPanel(panels.ObjectPanel):
557 """
558 A panel which displays the power utilization statistics for a device.
559 """
560 template_name = 'dcim/panels/power_utilization.html'
561 title = _('Power Utilization')
563 def get_context(self, context):
564 return {
565 **super().get_context(context),
566 'vc_members': context.get('vc_members'),
567 }
569 def should_render(self, context):
570 obj = context['object']
571 return obj.powerports.exists() and obj.poweroutlets.exists()
574class InterfacePanel(panels.ObjectAttributesPanel):
575 device = attrs.RelatedObjectAttr('device', linkify=True)
576 module = attrs.RelatedObjectAttr('module', linkify=True)
577 name = attrs.TextAttr('name')
578 label = attrs.TextAttr('label')
579 type = attrs.ChoiceAttr('type')
580 channels = attrs.NumericAttr('channels')
581 speed = attrs.TemplatedAttr('speed', template_name='dcim/interface/attrs/speed.html', label=_('Speed'))
582 duplex = attrs.ChoiceAttr('duplex')
583 mtu = attrs.NumericAttr('mtu', label=_('MTU'))
584 enabled = attrs.BooleanAttr('enabled')
585 mgmt_only = attrs.BooleanAttr('mgmt_only', label=_('Management only'))
586 description = attrs.TextAttr('description')
587 poe_mode = attrs.ChoiceAttr('poe_mode', label=_('PoE mode'))
588 poe_type = attrs.ChoiceAttr('poe_type', label=_('PoE type'))
589 mode = attrs.ChoiceAttr('mode', label=_('802.1Q mode'))
590 qinq_svlan = attrs.RelatedObjectAttr('qinq_svlan', linkify=True, label=_('Q-in-Q SVLAN'))
591 untagged_vlan = attrs.RelatedObjectAttr('untagged_vlan', linkify=True, label=_('Untagged VLAN'))
592 tx_power = attrs.TextAttr('tx_power', label=_('Transmit power'), format_string='{} dBm')
593 tunnel = attrs.RelatedObjectAttr('tunnel_termination.tunnel', linkify=True, label=_('Tunnel'))
594 l2vpn = attrs.RelatedObjectAttr('l2vpn_termination.l2vpn', linkify=True, label=_('L2VPN'))
597class RelatedInterfacesPanel(panels.ObjectAttributesPanel):
598 title = _('Related Interfaces')
600 parent = attrs.RelatedObjectAttr('parent', linkify=True)
601 channel_id = attrs.NumericAttr('channel_id', label=_('Channel ID'))
602 bridge = attrs.RelatedObjectAttr('bridge', linkify=True)
603 lag = attrs.RelatedObjectAttr('lag', linkify=True, label=_('LAG'))
606class InterfaceAddressingPanel(panels.ObjectAttributesPanel):
607 title = _('Addressing')
609 mac_address = attrs.TemplatedAttr(
610 'primary_mac_address',
611 template_name='dcim/interface/attrs/mac_address.html',
612 label=_('MAC address'),
613 )
614 wwn = attrs.TextAttr('wwn', style='font-monospace', label=_('WWN'))
615 vrf = attrs.RelatedObjectAttr('vrf', linkify=True, label=_('VRF'))
616 vlan_translation = attrs.RelatedObjectAttr('vlan_translation_policy', linkify=True, label=_('VLAN translation'))
619class InterfaceConnectionPanel(panels.ObjectPanel):
620 """
621 A connection panel for interfaces, which handles cable, wireless link, and virtual circuit cases.
622 """
623 template_name = 'dcim/panels/interface_connection.html'
624 title = _('Connection')
626 def should_render(self, context):
627 obj = context.get('object')
628 return False if (obj is None or obj.is_virtual) else True
631class VirtualCircuitPanel(panels.ObjectPanel):
632 """
633 A panel which displays virtual circuit information for a virtual interface.
634 """
635 template_name = 'dcim/panels/interface_virtual_circuit.html'
636 title = _('Virtual Circuit')
638 def should_render(self, context):
639 obj = context.get('object')
640 if not obj or not obj.is_virtual or not hasattr(obj, 'virtual_circuit_termination'):
641 return False
642 return True
645class InterfaceWirelessPanel(panels.ObjectPanel):
646 """
647 A panel which displays wireless RF attributes for an interface, comparing local and peer values.
648 """
649 template_name = 'dcim/panels/interface_wireless.html'
650 title = _('Wireless')
652 def should_render(self, context):
653 obj = context.get('object')
654 return False if (obj is None or not obj.is_wireless) else True
657class WirelessLANsPanel(panels.ObjectPanel):
658 """
659 A panel which lists the wireless LANs associated with an interface.
660 """
661 template_name = 'dcim/panels/interface_wireless_lans.html'
662 title = _('Wireless LANs')
664 def should_render(self, context):
665 obj = context.get('object')
666 return False if (obj is None or not obj.is_wireless) else True