diff --git a/netbox/dcim/ui/panels.py b/netbox/dcim/ui/panels.py index e4845bfc0..62435bedf 100644 --- a/netbox/dcim/ui/panels.py +++ b/netbox/dcim/ui/panels.py @@ -89,6 +89,8 @@ class DevicePanel(panels.ObjectAttributesPanel): class DeviceManagementPanel(panels.ObjectAttributesPanel): + title = _('Management') + status = attrs.ChoiceAttr('status') role = attrs.NestedObjectAttr('role', linkify=True, max_depth=3) platform = attrs.NestedObjectAttr('platform', linkify=True, max_depth=3) @@ -111,6 +113,8 @@ class DeviceManagementPanel(panels.ObjectAttributesPanel): class DeviceDimensionsPanel(panels.ObjectAttributesPanel): + title = _('Dimensions') + height = attrs.TextAttr('device_type.u_height', format_string='{}U') total_weight = attrs.TemplatedAttr('total_weight', template_name='dcim/device/attrs/total_weight.html') @@ -144,13 +148,32 @@ class VirtualChassisMembersPanel(panels.ObjectPanel): title = _('Virtual Chassis Members') def get_context(self, context): - """ - Return the context data to be used when rendering the panel. - - Parameters: - context: The template context - """ return { **super().get_context(context), 'vc_members': context.get('vc_members'), } + + def render(self, context): + if not context.get('vc_members'): + return '' + return super().render(context) + + +class PowerUtilizationPanel(panels.ObjectPanel): + """ + A panel which displays the power utilization statistics for a device. + """ + template_name = 'dcim/panels/power_utilization.html' + title = _('Power Utilization') + + def get_context(self, context): + return { + **super().get_context(context), + 'vc_members': context.get('vc_members'), + } + + def render(self, context): + obj = context['object'] + if not obj.powerports.exists() or not obj.poweroutlets.exists(): + return '' + return super().render(context) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 9f7b3f06a..b8a9e134a 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2456,7 +2456,7 @@ class DeviceView(generic.ObjectView): ], right_panels=[ panels.DeviceManagementPanel(), - # TODO: Power utilization + panels.PowerUtilizationPanel(), ObjectsTablePanel( model='ipam.Service', title=_('Application Services'), @@ -2472,9 +2472,8 @@ class DeviceView(generic.ObjectView): ], ), ImageAttachmentsPanel(), - panels.DeviceDimensionsPanel(title=_('Dimensions')), - # TODO: Rack elevations - # TemplatePanel('dcim/panels/rack_elevations.html'), + panels.DeviceDimensionsPanel(), + TemplatePanel('dcim/panels/device_rack_elevations.html'), ], ) diff --git a/netbox/templates/dcim/panels/device_rack_elevations.html b/netbox/templates/dcim/panels/device_rack_elevations.html new file mode 100644 index 000000000..1816be5c9 --- /dev/null +++ b/netbox/templates/dcim/panels/device_rack_elevations.html @@ -0,0 +1,26 @@ +{% load i18n %} +{% if object.rack and object.position %} +
+
+ {{ object.rack.name }} + {% if object.rack.role %} +
{{ object.rack.role }} + {% endif %} + {% if object.rack.facility_id %} +
{{ object.rack.facility_id }} + {% endif %} +
+
+
+

{% trans "Front" %}

+ {% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' extra_params=svg_extra %} +
+
+
+
+

{% trans "Rear" %}

+ {% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' extra_params=svg_extra %} +
+
+
+{% endif %} diff --git a/netbox/templates/dcim/panels/power_utilization.html b/netbox/templates/dcim/panels/power_utilization.html new file mode 100644 index 000000000..b716ed2c9 --- /dev/null +++ b/netbox/templates/dcim/panels/power_utilization.html @@ -0,0 +1,50 @@ +{% extends "ui/panels/_base.html" %} +{% load helpers i18n %} + +{% block panel_content %} + + + + + + + + + + + {% for powerport in object.powerports.all %} + {% with utilization=powerport.get_power_draw powerfeed=powerport.connected_endpoints.0 %} + + + + + {% if powerfeed.available_power %} + + + {% else %} + + + {% endif %} + + {% for leg in utilization.legs %} + + + + + {% if powerfeed.available_power %} + {% with phase_available=powerfeed.available_power|divide:3 %} + + + {% endwith %} + {% else %} + + + {% endif %} + + {% endfor %} + {% endwith %} + {% endfor %} +
{% trans "Input" %}{% trans "Outlets" %}{% trans "Allocated" %}{% trans "Available" %}{% trans "Utilization" %}
{{ powerport }}{{ utilization.outlet_count }}{{ utilization.allocated }}{% trans "VA" %}{{ powerfeed.available_power }}{% trans "VA" %}{% utilization_graph utilization.allocated|percentage:powerfeed.available_power %}
+ {% trans "Leg" context "Leg of a power feed" %} {{ leg.name }} + {{ leg.outlet_count }}{{ leg.allocated }}{{ phase_available }}{% trans "VA" %}{% utilization_graph leg.allocated|percentage:phase_available %}
+{% endblock panel_content %}