fix: render rack integrations server-side

This commit is contained in:
2026-08-13 10:15:13 +02:00
parent 33490d40c4
commit 270d821219
9 changed files with 302 additions and 11 deletions
@@ -54,3 +54,30 @@ class OptionalRackIntegrationHeadTest(SimpleTestCase):
self.assertIn('id="netbox-utilities-topology-rack-width-data"', html)
self.assertIn("netbox_utilities/topology-rack-width.js", html)
self.assertIn('"status": "ready"', html)
def test_topology_widths_are_rendered_server_side_without_javascript(self):
data = {
"devices": [
{
"device_id": 17,
"url": "/dcim/devices/17/",
"left_percent": 50,
"width_percent": 50,
}
],
"status": "ready",
"schema_version": 3,
"complete": True,
}
with (
patch("netbox_utilities.template_content.get_reorder_rack_width_data", return_value=None),
patch("netbox_utilities.template_content.get_topology_rack_width_data", return_value=data),
):
html = UtilitiesGlobalContent(
self._context("/plugins/netbox_topology_views/rack-elevation/?rack_id=3")
).head()
self.assertIn('id="netbox-utilities-topology-rack-width-styles"', html)
self.assertIn('.rack-device[href="/dcim/devices/17/"]', html)
self.assertIn("left: calc(50% + 3px) !important", html)
self.assertIn("width: calc(50% - 6px) !important", html)
+121 -2
View File
@@ -3,7 +3,9 @@ from pathlib import Path
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from django.template.loader import get_template, render_to_string
from django.test import RequestFactory, SimpleTestCase
from django.urls import resolve, reverse
from rest_framework.exceptions import PermissionDenied
from netbox_utilities.reorder_rack import (
@@ -16,6 +18,7 @@ from netbox_utilities.reorder_rack import (
install_reorder_rack_bulk_save,
parse_device_placements,
reorder_grid_y,
width_aware_reorder_get,
)
@@ -297,6 +300,110 @@ class ReorderRackFrontendTest(SimpleTestCase):
self.assertNotIn("partialDeviceIds", script)
self.assertNotIn("JSON.stringify", script)
def test_server_template_uses_complete_twelve_column_device_payload(self):
templates = Path(__file__).parents[1] / "templates" / "netbox_utilities"
page = (templates / "reorder_rack.html").read_text(encoding="utf-8")
grid = (templates / "reorder_rack_grid.html").read_text(encoding="utf-8")
self.assertIn('include "netbox_utilities/reorder_rack_grid.html"', page)
self.assertIn('gs-column="12"', grid)
self.assertIn("{% for device in reorder_devices %}", grid)
self.assertIn('gs-w="{{ device.grid_width }}"', grid)
self.assertIn('gs-x="{{ device.grid_x }}"', grid)
get_template("netbox_utilities/reorder_rack.html")
rendered_grid = render_to_string(
"netbox_utilities/reorder_rack_grid.html",
{
"object": SimpleNamespace(units=[1], u_height=42),
"face": "front",
"grid_id": 0,
"reorder_devices": [
{
"id": 10,
"label": "LEO-Fritzbox",
"face": "front",
"full_depth": False,
"grid_x": 0,
"grid_y": 62,
"grid_width": 6,
"grid_height": 2,
"width": 2,
"horizontal_position": 1,
"color": "f0a000",
"text_color": "000000",
"locked": False,
}
],
},
)
self.assertIn('gs-column="12"', rendered_grid)
self.assertIn('gs-id="10"', rendered_grid)
self.assertIn("LEO-Fritzbox", rendered_grid)
def test_resolved_reorder_page_uses_server_side_width_view(self):
view_class = resolve(reverse("dcim:rack_reorder", kwargs={"pk": 3})).func.view_class
self.assertIs(view_class.get, width_aware_reorder_get)
self.assertEqual(view_class.get.__module__, "netbox_utilities.reorder_rack")
@patch("netbox_utilities.reorder_rack.get_reorder_rack_width_data")
@patch("netbox_utilities.reorder_rack.get_object_or_404")
@patch("netbox_utilities.reorder_rack.Device")
@patch("django.shortcuts.render")
def test_server_side_reorder_view_renders_payload_devices(
self,
render_mock,
device_model,
get_object,
get_width_data,
):
from dcim.models import Rack, Site
rack = Rack(
pk=3,
name="Rack02 - Rechts",
site=Site(pk=1, name="AWO-MWT Leonardo Schule", slug="leonardo"),
u_height=42,
)
get_object.return_value = rack
device_model.objects.filter.return_value.exclude.return_value.select_related.return_value = []
get_width_data.return_value = {
"complete": True,
"unit_width": 220,
"devices": [
{
"id": 10,
"label": "LEO-Fritzbox",
"face": "front",
"full_depth": False,
"grid_x": 0,
"grid_y": 62,
"grid_width": 6,
"grid_height": 2,
"width": 2,
"horizontal_position": 1,
"color": "f0a000",
"text_color": "000000",
"locked": False,
}
],
}
request = RequestFactory().get("/dcim/racks/3/reorder/")
request.user = MagicMock()
request.user.is_authenticated = True
expected_response = SimpleNamespace(status_code=200)
render_mock.return_value = expected_response
response = width_aware_reorder_get(SimpleNamespace(), request, 3)
self.assertIs(response, expected_response)
template_name = render_mock.call_args.args[1]
context = render_mock.call_args.args[2]
self.assertEqual(template_name, "netbox_utilities/reorder_rack.html")
self.assertEqual(context["reorder_devices"][0]["label"], "LEO-Fritzbox")
self.assertEqual(context["reorder_devices"][0]["grid_width"], 6)
@patch("netbox_utilities.reorder_rack.reorder_rack_width_enabled", return_value=True)
@patch("netbox_utilities.reorder_rack.Rack")
def test_malformed_partial_placement_fails_open(self, rack_model, _enabled):
@@ -433,22 +540,34 @@ class ReorderRackPatchTest(SimpleTestCase):
def test_patches_supported_plugin_only_once(self):
original_update = object()
def original_get(self, request, pk):
return self, request, pk
class SaveViewSet:
update = original_update
views = SimpleNamespace(SaveViewSet=SaveViewSet)
class ReorderView:
get = original_get
api_views = SimpleNamespace(SaveViewSet=SaveViewSet)
page_views = SimpleNamespace(ReorderView=ReorderView)
plugin_config = SimpleNamespace(version="1.1.4")
with (
patch("netbox_utilities.reorder_rack.apps.is_installed", return_value=True),
patch("netbox_utilities.reorder_rack.apps.get_app_config", return_value=plugin_config),
patch("netbox_utilities.reorder_rack.import_module", return_value=views),
patch(
"netbox_utilities.reorder_rack.import_module",
side_effect=lambda name: api_views if name.endswith("api.views") else page_views,
),
):
self.assertTrue(install_reorder_rack_bulk_save())
self.assertTrue(install_reorder_rack_bulk_save())
self.assertIs(SaveViewSet.update, bulk_reorder_update)
self.assertIs(SaveViewSet._netbox_utilities_original_update, original_update)
self.assertIs(ReorderView.get, width_aware_reorder_get)
self.assertIs(ReorderView._netbox_utilities_original_get, original_get)
def test_skips_unsupported_plugin_version(self):
with (