Skip to content

Commit e55a4ae

Browse files
committed
Finish layout for device view
1 parent 60cc009 commit e55a4ae

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

netbox/dcim/ui/panels.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class DevicePanel(panels.ObjectAttributesPanel):
8989

9090

9191
class DeviceManagementPanel(panels.ObjectAttributesPanel):
92+
title = _('Management')
93+
9294
status = attrs.ChoiceAttr('status')
9395
role = attrs.NestedObjectAttr('role', linkify=True, max_depth=3)
9496
platform = attrs.NestedObjectAttr('platform', linkify=True, max_depth=3)
@@ -111,6 +113,8 @@ class DeviceManagementPanel(panels.ObjectAttributesPanel):
111113

112114

113115
class DeviceDimensionsPanel(panels.ObjectAttributesPanel):
116+
title = _('Dimensions')
117+
114118
height = attrs.TextAttr('device_type.u_height', format_string='{}U')
115119
total_weight = attrs.TemplatedAttr('total_weight', template_name='dcim/device/attrs/total_weight.html')
116120

@@ -144,13 +148,32 @@ class VirtualChassisMembersPanel(panels.ObjectPanel):
144148
title = _('Virtual Chassis Members')
145149

146150
def get_context(self, context):
147-
"""
148-
Return the context data to be used when rendering the panel.
151+
return {
152+
**super().get_context(context),
153+
'vc_members': context.get('vc_members'),
154+
}
155+
156+
def render(self, context):
157+
if not context.get('vc_members'):
158+
return ''
159+
return super().render(context)
149160

150-
Parameters:
151-
context: The template context
152-
"""
161+
162+
class PowerUtilizationPanel(panels.ObjectPanel):
163+
"""
164+
A panel which displays the power utilization statistics for a device.
165+
"""
166+
template_name = 'dcim/panels/power_utilization.html'
167+
title = _('Power Utilization')
168+
169+
def get_context(self, context):
153170
return {
154171
**super().get_context(context),
155172
'vc_members': context.get('vc_members'),
156173
}
174+
175+
def render(self, context):
176+
obj = context['object']
177+
if not obj.powerports.exists() or not obj.poweroutlets.exists():
178+
return ''
179+
return super().render(context)

netbox/dcim/views.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,7 +2456,7 @@ class DeviceView(generic.ObjectView):
24562456
],
24572457
right_panels=[
24582458
panels.DeviceManagementPanel(),
2459-
# TODO: Power utilization
2459+
panels.PowerUtilizationPanel(),
24602460
ObjectsTablePanel(
24612461
model='ipam.Service',
24622462
title=_('Application Services'),
@@ -2472,9 +2472,8 @@ class DeviceView(generic.ObjectView):
24722472
],
24732473
),
24742474
ImageAttachmentsPanel(),
2475-
panels.DeviceDimensionsPanel(title=_('Dimensions')),
2476-
# TODO: Rack elevations
2477-
# TemplatePanel('dcim/panels/rack_elevations.html'),
2475+
panels.DeviceDimensionsPanel(),
2476+
TemplatePanel('dcim/panels/device_rack_elevations.html'),
24782477
],
24792478
)
24802479

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% load i18n %}
2+
{% if object.rack and object.position %}
3+
<div class="row" style="margin-bottom: 20px">
4+
<div class="text-center">
5+
<strong><a href="{% url 'dcim:rack' pk=object.rack.pk %}">{{ object.rack.name }}</a></strong>
6+
{% if object.rack.role %}
7+
<br /><span class="badge my-3" style="color: {{ object.rack.role.color|fgcolor }}; background-color: #{{ object.rack.role.color }}">{{ object.rack.role }}</span>
8+
{% endif %}
9+
{% if object.rack.facility_id %}
10+
<br /><small class="text-muted">{{ object.rack.facility_id }}</small>
11+
{% endif %}
12+
</div>
13+
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
14+
<div style="margin-left: 30px">
15+
<h2 class="h4">{% trans "Front" %}</h2>
16+
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' extra_params=svg_extra %}
17+
</div>
18+
</div>
19+
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
20+
<div style="margin-left: 30px">
21+
<h2 class="h4">{% trans "Rear" %}</h2>
22+
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' extra_params=svg_extra %}
23+
</div>
24+
</div>
25+
</div>
26+
{% endif %}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{% extends "ui/panels/_base.html" %}
2+
{% load helpers i18n %}
3+
4+
{% block panel_content %}
5+
<table class="table table-hover">
6+
<thead>
7+
<tr>
8+
<th>{% trans "Input" %}</th>
9+
<th>{% trans "Outlets" %}</th>
10+
<th>{% trans "Allocated" %}</th>
11+
<th>{% trans "Available" %}</th>
12+
<th>{% trans "Utilization" %}</th>
13+
</tr>
14+
</thead>
15+
{% for powerport in object.powerports.all %}
16+
{% with utilization=powerport.get_power_draw powerfeed=powerport.connected_endpoints.0 %}
17+
<tr>
18+
<td>{{ powerport }}</td>
19+
<td>{{ utilization.outlet_count }}</td>
20+
<td>{{ utilization.allocated }}{% trans "VA" %}</td>
21+
{% if powerfeed.available_power %}
22+
<td>{{ powerfeed.available_power }}{% trans "VA" %}</td>
23+
<td>{% utilization_graph utilization.allocated|percentage:powerfeed.available_power %}</td>
24+
{% else %}
25+
<td class="text-muted">&mdash;</td>
26+
<td class="text-muted">&mdash;</td>
27+
{% endif %}
28+
</tr>
29+
{% for leg in utilization.legs %}
30+
<tr>
31+
<td style="padding-left: 20px">
32+
{% trans "Leg" context "Leg of a power feed" %} {{ leg.name }}
33+
</td>
34+
<td>{{ leg.outlet_count }}</td>
35+
<td>{{ leg.allocated }}</td>
36+
{% if powerfeed.available_power %}
37+
{% with phase_available=powerfeed.available_power|divide:3 %}
38+
<td>{{ phase_available }}{% trans "VA" %}</td>
39+
<td>{% utilization_graph leg.allocated|percentage:phase_available %}</td>
40+
{% endwith %}
41+
{% else %}
42+
<td class="text-muted">&mdash;</td>
43+
<td class="text-muted">&mdash;</td>
44+
{% endif %}
45+
</tr>
46+
{% endfor %}
47+
{% endwith %}
48+
{% endfor %}
49+
</table>
50+
{% endblock panel_content %}

0 commit comments

Comments
 (0)