12489 Use HTMX for Location and Non-Racked Devices in Site detail view (#12491)

* 12489 use htmx for site view locations and non-racked-devices

* 12489 remove now unused queries in context

* adds device type and role to device component filter #12015

* Revert "Fixes #12463: Fix the association of completed jobs with reports & scripts in the REST API"

This reverts commit a29a07ed26.

* 12489 update nonracked_devices on rack and location templates

* 12489 fix whitespace issue

* Undo errant commits

* 12489 update site id in templates

* 12489 remove nonracked_devices include

* 12489 add has_position filter

* Use empty lookup for position field

* Remove non-racked devices list from rack view (was moved to a tab)

* Clean up location and device tables

* Restore plugins block on rack template

---------

Co-authored-by: Abhimanyu Saharan <desk.abhimanyu@gmail.com>
Co-authored-by: jeremystretch <jstretch@netboxlabs.com>
This commit is contained in:
Arthur Hanson 2023-08-28 13:03:35 -07:00 committed by GitHub
parent 480f83c42d
commit 29877c9abe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 153 deletions

View File

@ -398,32 +398,8 @@ class SiteView(generic.ObjectView):
(Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(), 'site_id'), (Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(), 'site_id'),
) )
locations = Location.objects.add_related_count(
Location.objects.all(),
Rack,
'location',
'rack_count',
cumulative=True
)
locations = Location.objects.add_related_count(
locations,
Device,
'location',
'device_count',
cumulative=True
).restrict(request.user, 'view').filter(site=instance)
nonracked_devices = Device.objects.filter(
site=instance,
rack__isnull=True,
parent_bay__isnull=True
).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role')
return { return {
'related_models': related_models, 'related_models': related_models,
'locations': locations,
'nonracked_devices': nonracked_devices.order_by('-pk')[:10],
'total_nonracked_devices_count': nonracked_devices.count(),
} }
@ -495,16 +471,8 @@ class LocationView(generic.ObjectView):
(Device.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'), (Device.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'),
) )
nonracked_devices = Device.objects.filter(
location=instance,
rack__isnull=True,
parent_bay__isnull=True
).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role')
return { return {
'related_models': related_models, 'related_models': related_models,
'nonracked_devices': nonracked_devices.order_by('-pk')[:10],
'total_nonracked_devices_count': nonracked_devices.count(),
} }

View File

@ -1,76 +0,0 @@
{% load helpers %}
<div class="card">
<h5 class="card-header">
Non-Racked Devices
</h5>
<div class="card-body">
{% if nonracked_devices %}
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Role</th>
<th>Type</th>
<th colspan="2">Parent Device</th>
</tr>
{% for device in nonracked_devices %}
<tr{% if device.device_type.u_height %} class="warning"{% endif %}>
<td>
<a href="{% url 'dcim:device' pk=device.pk %}">{{ device }}</a>
</td>
<td>{{ device.device_role }}</td>
<td>{{ device.device_type }}</td>
{% if device.parent_bay %}
<td>{{ device.parent_bay.device|linkify }}</td>
<td>{{ device.parent_bay }}</td>
{% else %}
<td colspan="2" class="text-muted">&mdash;</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% if total_nonracked_devices_count > nonracked_devices.count %}
{% if object|meta:'verbose_name' == 'site' %}
<div class="text-muted">
Displaying {{ nonracked_devices.count }} of {{ total_nonracked_devices_count }} devices (<a href="{% url 'dcim:device_list' %}?site_id={{ object.pk }}&rack_id=null">View full list</a>)
</div>
{% elif object|meta:'verbose_name' == 'location' %}
<div class="text-muted">
Displaying {{ nonracked_devices.count }} of {{ total_nonracked_devices_count }} devices (<a href="{% url 'dcim:device_list' %}?location_id={{ object.pk }}&rack_id=null">View full list</a>)
</div>
{% endif %}
{% endif %}
{% else %}
<div class="text-muted">
None
</div>
{% endif %}
</div>
{% if perms.dcim.add_device %}
{% if object|meta:'verbose_name' == 'rack' %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:device_add' %}?site={{ object.site.pk }}&rack={{ object.pk }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i>
Add a Non-Racked Device
</a>
</div>
{% elif object|meta:'verbose_name' == 'site' %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:device_add' %}?site={{ object.pk }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i>
Add a Non-Racked Device
</a>
</div>
{% elif object|meta:'verbose_name' == 'location' %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:device_add' %}?site={{ object.site.pk }}&location={{ object.pk }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i>
Add a Non-Racked Device
</a>
</div>
{% endif %}
{% endif %}
</div>

View File

@ -65,7 +65,6 @@
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/related_objects.html' %}
{% include 'dcim/inc/nonracked_devices.html' %}
{% include 'inc/panels/image_attachments.html' %} {% include 'inc/panels/image_attachments.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
@ -78,6 +77,27 @@
hx-get="{% url 'dcim:location_list' %}?parent_id={{ object.pk }}" hx-get="{% url 'dcim:location_list' %}?parent_id={{ object.pk }}"
hx-trigger="load" hx-trigger="load"
></div> ></div>
{% if perms.dcim.add_location %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:location_add' %}?site={{ object.site.pk }}&parent={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Location
</a>
</div>
{% endif %}
</div>
<div class="card">
<h5 class="card-header">Non-Racked Devices</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:device_list' %}?location_id={{ object.pk }}&rack_id=null&parent_bay_id=null"
hx-trigger="load"
></div>
{% if perms.dcim.add_device %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:device_add' %}?site={{ object.site.pk }}&location={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Device
</a>
</div>
{% endif %}
</div> </div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>

View File

@ -131,56 +131,40 @@
</div> </div>
<div class="col col-md-6"> <div class="col col-md-6">
{% include 'inc/panels/related_objects.html' with filter_name='site_id' %} {% include 'inc/panels/related_objects.html' with filter_name='site_id' %}
<div class="card">
<h5 class="card-header">Locations</h5>
<div class='card-body'>
{% if locations %}
<table class="table table-hover">
<tr>
<th>Location</th>
<th>Racks</th>
<th>Devices</th>
<th></th>
</tr>
{% for location in locations %}
<tr>
<td>
{% for i in location.level|as_range %}<i class="mdi mdi-circle-small"></i>{% endfor %}
{{ location|linkify }}
</td>
<td>
<a href="{% url 'dcim:rack_list' %}?location_id={{ location.pk }}">{{ location.rack_count }}</a>
</td>
<td>
<a href="{% url 'dcim:device_list' %}?location_id={{ location.pk }}">{{ location.device_count }}</a>
</td>
<td class="text-end noprint">
<a href="{% url 'dcim:rack_elevation_list' %}?location_id={{ location.pk }}" class="btn btn-sm btn-primary" title="View Elevations">
<i class="mdi mdi-server"></i>
</a>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<span class="text-muted">None</span>
{% endif %}
</div>
{% if perms.dcim.add_location %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:location_add' %}?site={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a location
</a>
</div>
{% endif %}
</div>
{% include 'inc/panels/image_attachments.html' %} {% include 'inc/panels/image_attachments.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col col-md-12"> <div class="col col-md-12">
{% include 'dcim/inc/nonracked_devices.html' %} <div class="card">
<h5 class="card-header">Locations</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:location_list' %}?site_id={{ object.pk }}"
hx-trigger="load"
></div>
{% if perms.dcim.add_location %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:location_add' %}?site={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Location
</a>
</div>
{% endif %}
</div>
<div class="card">
<h5 class="card-header">Non-Racked Devices</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'dcim:device_list' %}?site_id={{ object.pk }}&rack_id=null&parent_bay_id=null"
hx-trigger="load"
></div>
{% if perms.dcim.add_device %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:device_add' %}?site={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Device
</a>
</div>
{% endif %}
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>