Skip to content

Commit

Permalink
Closes netbox-community#951: Provide a side-by-side view of rack elev…
Browse files Browse the repository at this point in the history
…ations
  • Loading branch information
jeremystretch committed Apr 20, 2017
1 parent 72ffedc commit ecebfa9
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 54 deletions.
9 changes: 4 additions & 5 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import re

from mptt.forms import TreeNodeChoiceField
import re

from django import forms
from django.contrib.postgres.forms.array import SimpleArrayField
Expand All @@ -21,9 +20,9 @@
DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_PLANNED, CONNECTION_STATUS_CONNECTED,
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceRole, DeviceType,
Interface, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate,
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_TYPE_CHOICES,
RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD,
SUBDEVICE_ROLE_PARENT, VIRTUAL_IFACE_TYPES
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate,
RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, Region, Site, STATUS_CHOICES,
SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, VIRTUAL_IFACE_TYPES,
)


Expand Down
1 change: 1 addition & 0 deletions netbox/dcim/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

# Racks
url(r'^racks/$', views.RackListView.as_view(), name='rack_list'),
url(r'^rack-elevations/$', views.RackElevationListView.as_view(), name='rack_elevation_list'),
url(r'^racks/add/$', views.RackEditView.as_view(), name='rack_add'),
url(r'^racks/import/$', views.RackBulkImportView.as_view(), name='rack_import'),
url(r'^racks/edit/$', views.RackBulkEditView.as_view(), name='rack_bulk_edit'),
Expand Down
42 changes: 42 additions & 0 deletions netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.paginator import EmptyPage, PageNotAnInteger
from django.db.models import Count
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
Expand All @@ -17,6 +18,7 @@
from circuits.models import Circuit
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
from utilities.forms import ConfirmationForm
from utilities.paginator import EnhancedPaginator
from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
)
Expand Down Expand Up @@ -291,6 +293,46 @@ class RackListView(ObjectListView):
template_name = 'dcim/rack_list.html'


class RackElevationListView(View):
"""
Display a set of rack elevations side-by-side.
"""

def get(self, request):

racks = Rack.objects.select_related(
'site', 'group', 'tenant', 'role'
).prefetch_related(
'devices__device_type'
)
racks = filters.RackFilter(request.GET, racks).qs
total_count = racks.count()

# Pagination
paginator = EnhancedPaginator(racks, 25)
page_number = request.GET.get('page', 1)
try:
page = paginator.page(page_number)
except PageNotAnInteger:
page = paginator.page(1)
except EmptyPage:
page = paginator.page(paginator.num_pages)

# Determine rack face
if request.GET.get('face') == '1':
face_id = 1
else:
face_id = 0

return render(request, 'dcim/rack_elevation_list.html', {
'paginator': paginator,
'page': page,
'total_count': total_count,
'face_id': face_id,
'filter_form': forms.RackFilterForm(request.GET),
})


def rack(request, pk):

rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
Expand Down
1 change: 1 addition & 0 deletions netbox/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Racks <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'dcim:rack_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Racks</a></li>
<li><a href="{% url 'dcim:rack_elevation_list' %}"><i class="fa fa-bars" aria-hidden="true"></i> Rack Elevations</a></li>
{% if perms.dcim.add_rack %}
<li><a href="{% url 'dcim:rack_add' %}"><i class="fa fa-plus" aria-hidden="true"></i> Add a Rack</a></li>
<li><a href="{% url 'dcim:rack_import' %}"><i class="fa fa-download" aria-hidden="true"></i> Import Racks</a></li>
Expand Down
50 changes: 50 additions & 0 deletions netbox/templates/dcim/rack_elevation_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{% extends '_base.html' %}
{% load helpers %}

{% block content %}
<div class="btn-group pull-right" role="group">
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face=0 %}" class="btn btn-default{% if request.GET.face != '1' %} active{% endif %}">Front</a>
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face=1 %}" class="btn btn-default{% if request.GET.face == '1' %} active{% endif %}">Rear</a>
</div>
<h1>{% block title %}Rack Elevations{% endblock %}</h1>
<div class="row">
{% if page %}
<div class="col-md-9">
<div style="white-space: nowrap; overflow-x: scroll;">
{% for rack in page %}
<div style="display: inline-block; width: 266px">
<div class="rack_header">
<h4>{{ rack.name }}</h4>
</div>
{% if face_id %}
{% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_rear_elevation secondary_face=rack.get_front_elevation face_id=1 %}
{% else %}
{% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_front_elevation secondary_face=rack.get_rear_elevation face_id=0 %}
{% endif %}
<div class="clearfix"></div>
<div class="rack_header">
<h4>{{ rack.name }}</h4>
</div>
</div>
{% endfor %}
</div>
{% include 'paginator.html' %}
</div>
{% else %}
<div class="col-md-9">
<p>No racks found</p>
</div>
{% endif %}
<div class="col-md-3">
{% include 'inc/search_panel.html' %}
</div>
</div>
{% endblock %}

{% block javascript %}
<script type="text/javascript">
$(function() {
$('[data-toggle="popover"]').popover()
})
</script>
{% endblock %}
13 changes: 4 additions & 9 deletions netbox/templates/ipam/prefix_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,10 @@

{% block content %}
<div class="pull-right">
<a href="{% url 'ipam:prefix_list' %}{% querystring_toggle request expand='on' %}" class="btn btn-default">
{% if 'expand' in request.GET %}
<span class="fa fa-chevron-right" aria-hidden="true"></span>
Collapse all
{% else %}
<span class="fa fa-chevron-down" aria-hidden="true"></span>
Expand all
{% endif %}
</a>
<div class="btn-group" role="group">
<a href="{% url 'ipam:prefix_list' %}{% querystring request expand=None page=1 %}" class="btn btn-default{% if not request.GET.expand %} active{% endif %}">Collapse</a>
<a href="{% url 'ipam:prefix_list' %}{% querystring request expand='on' page=1 %}" class="btn btn-default{% if request.GET.expand %} active{% endif %}">Expand</a>
</div>
{% if perms.ipam.add_prefix %}
<a href="{% url 'ipam:prefix_add' %}" class="btn btn-primary">
<span class="fa fa-plus" aria-hidden="true"></span>
Expand Down
27 changes: 10 additions & 17 deletions netbox/templates/paginator.html
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
{% load django_tables2 %}
{% load helpers %}

{# Custom pagination controls to render nicely with Bootstrap CSS. smart_pages requires EnhancedPaginator. #}

<div class="paginator pull-right">
{% if table.paginator.num_pages > 1 %}
<div class="paginator pull-right" style="margin-top: 20px">
{% if paginator.num_pages > 1 %}
<nav>
<ul class="pagination pull-right">
{% if table.page.has_previous %}
<li><a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">&laquo;</a></li>
{% if page.has_previous %}
<li><a href="{% querystring request page=page.previous_page_number %}">&laquo;</a></li>
{% endif %}
{% for p in table.page.smart_pages %}
{% for p in page.smart_pages %}
{% if p %}
<li{% ifequal table.page.number p %} class="active"{% endifequal %}><a href="{% querystring table.prefixed_page_field=p %}">{{ p }}</a></li>
<li{% ifequal page.number p %} class="active"{% endifequal %}><a href="{% querystring request page=p %}">{{ p }}</a></li>
{% else %}
<li class="disabled"><span>&hellip;</span></li>
{% endif %}
{% endfor %}
{% if table.page.has_next %}
<li><a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">&raquo;</a></li>
{% if page.has_next %}
<li><a href="{% querystring request page=page.next_page_number %}">&raquo;</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
<div class="clearfix"></div>
<div class="text-right text-muted">
Showing {{ table.page.start_index }}-{{ table.page.end_index }} of {{ total }}
{% if total == 1 %}
{{ table.data.verbose_name }}
{% else %}
{{ table.data.verbose_name_plural }}
{% endif %}
Showing {{ page.start_index }}-{{ page.end_index }} of {{ total_count }}
</div>
</div>
2 changes: 1 addition & 1 deletion netbox/templates/panel_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@

{% block pagination %}
{% if not hide_paginator %}
{% include 'paginator.html' %}
{% include 'table_paginator.html' %}
{% endif %}
{% endblock pagination %}
2 changes: 1 addition & 1 deletion netbox/templates/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@

{% block pagination %}
{% if not hide_paginator %}
{% include 'paginator.html' %}
{% include 'table_paginator.html' %}
{% endif %}
{% endblock pagination %}
34 changes: 34 additions & 0 deletions netbox/templates/table_paginator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{% load django_tables2 %}

{# Custom pagination controls to render nicely with Bootstrap CSS. smart_pages requires EnhancedPaginator. #}

<div class="paginator pull-right">
{% if table.paginator.num_pages > 1 %}
<nav>
<ul class="pagination pull-right">
{% if table.page.has_previous %}
<li><a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">&laquo;</a></li>
{% endif %}
{% for p in table.page.smart_pages %}
{% if p %}
<li{% ifequal table.page.number p %} class="active"{% endifequal %}><a href="{% querystring table.prefixed_page_field=p %}">{{ p }}</a></li>
{% else %}
<li class="disabled"><span>&hellip;</span></li>
{% endif %}
{% endfor %}
{% if table.page.has_next %}
<li><a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">&raquo;</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
<div class="clearfix"></div>
<div class="text-right text-muted">
Showing {{ table.page.start_index }}-{{ table.page.end_index }} of {{ total }}
{% if total == 1 %}
{{ table.data.verbose_name }}
{% else %}
{{ table.data.verbose_name_plural }}
{% endif %}
</div>
</div>
29 changes: 8 additions & 21 deletions netbox/utilities/templatetags/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,17 @@ def bettertitle(value):
#

@register.simple_tag()
def querystring_toggle(request, multi=True, page_key='page', **kwargs):
def querystring(request, **kwargs):
"""
Add or remove a parameter in the HTTP GET query string
Append or update the page number in a querystring.
"""
new_querydict = request.GET.copy()

# Remove page number from querystring
try:
new_querydict.pop(page_key)
except KeyError:
pass

# Add/toggle parameters
querydict = request.GET.copy()
for k, v in kwargs.items():
values = new_querydict.getlist(k)
if k in new_querydict and v in values:
values.remove(v)
new_querydict.setlist(k, values)
elif not multi:
new_querydict[k] = v
else:
new_querydict.update({k: v})

querystring = new_querydict.urlencode()
if v is not None:
querydict[k] = v
elif k in querydict:
querydict.pop(k)
querystring = querydict.urlencode()
if querystring:
return '?' + querystring
else:
Expand Down

0 comments on commit ecebfa9

Please sign in to comment.