diff --git a/README.md b/README.md index b440a5f..c2fa2e6 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Release-Tag oder ein bestimmter Commit verwendet werden: ```bash /opt/netbox/venv/bin/pip install --upgrade --force-reinstall \ - "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.8.1" + "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.8.2" ``` Alternativ kann hinter dem `@` die vollständige Commit-ID stehen. @@ -136,7 +136,7 @@ empfohlen. ### Mehrere Geräte nebeneinander in derselben HE Auf der normalen **Bearbeitungsseite eines Geräts** stehen direkt nach -**Rackseite** zwei neue optionale Felder zur Verfügung. Dafür wird kein +**Position** zwei neue optionale Felder zur Verfügung. Dafür wird kein separates Plugin-Menü benötigt: - **Rackbreite**: volle, halbe, Drittel- oder Viertelbreite; diff --git a/netbox_utilities/__init__.py b/netbox_utilities/__init__.py index 1fc09eb..4e29415 100644 --- a/netbox_utilities/__init__.py +++ b/netbox_utilities/__init__.py @@ -1,6 +1,6 @@ from netbox.plugins import PluginConfig, get_plugin_config -__version__ = "0.8.1" +__version__ = "0.8.2" class NetBoxUtilitiesConfig(PluginConfig): diff --git a/netbox_utilities/rack_width.py b/netbox_utilities/rack_width.py index 235c295..96c8d74 100644 --- a/netbox_utilities/rack_width.py +++ b/netbox_utilities/rack_width.py @@ -307,6 +307,7 @@ def _install_device_validation(): def _install_device_form(): from dcim.views import DeviceEditView + from netbox.registry import registry if getattr(DeviceEditView, "_netbox_utilities_rack_width_installed", False): return @@ -341,7 +342,7 @@ def _install_device_form(): if name in {"utilities_rack_width", "utilities_horizontal_position"}: continue reordered[name] = field - if name == "face": + if name == "position": reordered["utilities_rack_width"] = self.fields["utilities_rack_width"] reordered["utilities_horizontal_position"] = self.fields["utilities_horizontal_position"] self.fields = reordered @@ -379,6 +380,20 @@ def _install_device_form(): RackWidthDeviceForm.__module__ = __name__ RackWidthDeviceForm.__qualname__ = "RackWidthDeviceForm" + + class RackWidthDeviceEditView(DeviceEditView): + form = RackWidthDeviceForm + + RackWidthDeviceEditView.__module__ = __name__ + RackWidthDeviceEditView.__qualname__ = "RackWidthDeviceEditView" + + for view_config in registry["views"]["dcim"]["device"]: + if view_config["name"] == "edit": + view_config["view"] = RackWidthDeviceEditView + break + else: + raise RuntimeError("Die NetBox-Gerätebearbeitung ist nicht in der View-Registry registriert.") + DeviceEditView.form = RackWidthDeviceForm DeviceEditView._netbox_utilities_rack_width_installed = True diff --git a/netbox_utilities/tests/test_rack_width.py b/netbox_utilities/tests/test_rack_width.py index cc9d022..7402164 100644 --- a/netbox_utilities/tests/test_rack_width.py +++ b/netbox_utilities/tests/test_rack_width.py @@ -3,7 +3,9 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch from django.core.exceptions import ValidationError +from django.template.loader import render_to_string from django.test import SimpleTestCase +from django.urls import resolve, reverse from netbox_utilities.rack_width import ( _cleanup_unracked_placement, @@ -19,11 +21,45 @@ from netbox_utilities.rack_width import ( class RackWidthTest(SimpleTestCase): def test_device_edit_view_uses_explicit_rack_width_form(self): - from dcim.views import DeviceEditView + from netbox.registry import registry - self.assertEqual(DeviceEditView.form.__name__, "RackWidthDeviceForm") - self.assertIn("utilities_rack_width", DeviceEditView.form.base_fields) - self.assertIn("utilities_horizontal_position", DeviceEditView.form.base_fields) + edit_view = next(view["view"] for view in registry["views"]["dcim"]["device"] if view["name"] == "edit") + + self.assertEqual(edit_view.__name__, "RackWidthDeviceEditView") + self.assertEqual(edit_view.form.__name__, "RackWidthDeviceForm") + self.assertIn("utilities_rack_width", edit_view.form.base_fields) + self.assertIn("utilities_horizontal_position", edit_view.form.base_fields) + + def test_resolved_device_edit_page_renders_rack_width_fields(self): + from dcim.models import Device + + object_type = SimpleNamespace(pk=1, model_class=lambda: Device) + with ( + patch("core.models.ObjectType.objects.get_for_model", return_value=object_type), + patch( + "django.contrib.contenttypes.models.ContentType.objects.get_for_model", + return_value=object_type, + ), + patch("extras.models.CustomField.objects.get_for_model", return_value=[]), + patch( + "netbox_utilities.runtime._get_database_settings", + return_value={"tenant_required": True}, + ), + ): + url = reverse("dcim:device_edit", kwargs={"pk": 1}) + view_class = resolve(url).func.view_class + form = view_class.form() + html = render_to_string("htmx/form.html", {"form": form}) + + width = 'name="utilities_rack_width"' + horizontal_position = 'name="utilities_horizontal_position"' + self.assertIn(width, html) + self.assertIn(horizontal_position, html) + field_names = list(form.fields) + self.assertEqual( + field_names[field_names.index("position") : field_names.index("position") + 4], + ["position", "utilities_rack_width", "utilities_horizontal_position", "face"], + ) def test_normalizes_full_width_to_first_position(self): self.assertEqual(normalize_width_position(1, 4), (1, 1)) diff --git a/pyproject.toml b/pyproject.toml index 51543cf..c26f77f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "netbox-utilities" -version = "0.8.1" +version = "0.8.2" description = "Navigation, tenant utilities, partial-width rack devices, bulk uploads, and rack reordering for NetBox 4.6" readme = "README.md" requires-python = ">=3.12"