diff --git a/README.md b/README.md index ad9184b..9f2940d 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.3" + "git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.8.4" ``` Alternativ kann hinter dem `@` die vollständige Commit-ID stehen. diff --git a/netbox_utilities/__init__.py b/netbox_utilities/__init__.py index afc115a..e7e108e 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.3" +__version__ = "0.8.4" class NetBoxUtilitiesConfig(PluginConfig): diff --git a/netbox_utilities/rack_width.py b/netbox_utilities/rack_width.py index ae1bfae..80bc123 100644 --- a/netbox_utilities/rack_width.py +++ b/netbox_utilities/rack_width.py @@ -424,6 +424,8 @@ def _install_device_form(): class RackWidthDeviceEditView(DeviceEditView): form = RackWidthDeviceForm + template_name = "netbox_utilities/device_edit.html" + htmx_template_name = "netbox_utilities/device_edit_form.html" RackWidthDeviceEditView.__module__ = __name__ RackWidthDeviceEditView.__qualname__ = "RackWidthDeviceEditView" diff --git a/netbox_utilities/templates/netbox_utilities/device_edit.html b/netbox_utilities/templates/netbox_utilities/device_edit.html new file mode 100644 index 0000000..40fa740 --- /dev/null +++ b/netbox_utilities/templates/netbox_utilities/device_edit.html @@ -0,0 +1,5 @@ +{% extends 'dcim/device_edit.html' %} + +{% block form %} + {% include 'netbox_utilities/device_edit_form.html' %} +{% endblock form %} diff --git a/netbox_utilities/templates/netbox_utilities/device_edit_form.html b/netbox_utilities/templates/netbox_utilities/device_edit_form.html new file mode 100644 index 0000000..8dd82dd --- /dev/null +++ b/netbox_utilities/templates/netbox_utilities/device_edit_form.html @@ -0,0 +1,130 @@ +{% load form_helpers %} +{% load i18n %} + +{% for field in form.hidden_fields %} + {{ field }} +{% endfor %} + +
+
+

{% trans "Device" %}

+
+ {% render_field form.name %} + {% render_field form.role %} + {% render_field form.description %} + {% render_field form.tags %} +
+ +
+
+

{% trans "Hardware" %}

+
+ {% render_field form.device_type %} + {% render_field form.airflow %} + {% render_field form.serial %} + {% render_field form.asset_tag %} +
+ +
+
+

{% trans "Location" %}

+
+ {% render_field form.site %} + {% render_field form.location %} + {% render_field form.rack %} + + {% if object.device_type.is_child_device and object.parent_bay %} +
+ +
+ +
+
+
+ + +
+ {% else %} + {% render_field form.face %} + {% render_field form.position %} + {% render_field form.utilities_rack_width %} + {% render_field form.utilities_horizontal_position %} + {% render_field form.latitude %} + {% render_field form.longitude %} + {% endif %} +
+ +
+
+

{% trans "Management" %}

+
+ {% render_field form.status %} + {% render_field form.platform %} + {% render_field form.config_template %} + {% if object.pk %} + {% render_field form.primary_ip4 %} + {% render_field form.primary_ip6 %} + {% render_field form.oob_ip %} + {% endif %} +
+ +
+
+

{% trans "Virtualization" %}

+
+ {% render_field form.cluster %} +
+ +
+
+

{% trans "Tenancy" %}

+
+ {% render_field form.tenant_group %} + {% render_field form.tenant %} +
+ +
+
+

{% trans "Virtual Chassis" %}

+
+ {% render_field form.virtual_chassis %} + {% render_field form.vc_position %} + {% render_field form.vc_priority %} +
+ +
+
+

{% trans "Ownership" %}

+
+ {% render_field form.owner_group %} + {% render_field form.owner %} +
+ +{% if form.custom_fields %} +
+
+

{% trans "Custom Fields" %}

+
+ {% render_custom_fields form %} +
+{% endif %} + +
+

{% trans "Local Config Context Data" %}

+ {% render_field form.local_context_data %} +
+ +
+ {% render_field form.comments %} +
+ +
+ {% render_field form.changelog_message %} +
diff --git a/netbox_utilities/tests/test_rack_width.py b/netbox_utilities/tests/test_rack_width.py index bd2e240..ad8e64a 100644 --- a/netbox_utilities/tests/test_rack_width.py +++ b/netbox_utilities/tests/test_rack_width.py @@ -2,9 +2,12 @@ from importlib import import_module from types import SimpleNamespace from unittest.mock import MagicMock, patch +from django.conf import settings +from django.contrib.auth.context_processors import PermWrapper +from django.contrib.auth.models import AnonymousUser from django.core.exceptions import ValidationError from django.template.loader import render_to_string -from django.test import SimpleTestCase +from django.test import RequestFactory, SimpleTestCase from django.urls import resolve, reverse from netbox_utilities.rack_width import ( @@ -56,12 +59,13 @@ class RackWidthTest(SimpleTestCase): self.assertEqual(edit_view.__name__, "RackWidthDeviceEditView") self.assertEqual(edit_view.form.__name__, "RackWidthDeviceForm") + self.assertEqual(edit_view.template_name, "netbox_utilities/device_edit.html") + self.assertEqual(edit_view.htmx_template_name, "netbox_utilities/device_edit_form.html") 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 - from utilities.forms.rendering import FieldSet object_type = SimpleNamespace(pk=1, model_class=lambda: Device) with ( @@ -78,32 +82,43 @@ class RackWidthTest(SimpleTestCase): ): url = reverse("dcim:device_edit", kwargs={"pk": 1}) view_class = resolve(url).func.view_class - base_form = view_class.form.__mro__[1] - with patch.object( - base_form, - "fieldsets", - (FieldSet("site", "rack", "position", "face", "latitude", name="Location"),), - ): - form = view_class.form() - rendered_fieldsets = form.fieldsets - html = render_to_string("htmx/form.html", {"form": form}) + form = view_class.form() + request = self._anonymous_request() + context = { + "form": form, + "object": SimpleNamespace( + pk=None, + _meta=Device._meta, + device_type=SimpleNamespace(is_child_device=False), + parent_bay=None, + ), + "return_url": "/dcim/devices/", + "request": request, + "settings": settings, + "csrf_token": "", + "perms": PermWrapper(request.user), + } + rendered_pages = ( + render_to_string(view_class.htmx_template_name, context), + render_to_string(view_class.template_name, context), + ) + rack_position = 'name="position"' width = 'name="utilities_rack_width"' horizontal_position = 'name="utilities_horizontal_position"' - self.assertIn(width, html) - self.assertIn(horizontal_position, html) - self.assertEqual( - rendered_fieldsets[0].items, - ( - "site", - "rack", - "position", - "utilities_rack_width", - "utilities_horizontal_position", - "face", - "latitude", - ), - ) + latitude = 'name="latitude"' + for html in rendered_pages: + self.assertIn(width, html) + self.assertIn(horizontal_position, html) + self.assertLess(html.index(rack_position), html.index(width)) + self.assertLess(html.index(width), html.index(horizontal_position)) + self.assertLess(html.index(horizontal_position), html.index(latitude)) + + @staticmethod + def _anonymous_request(): + request = RequestFactory().get("/dcim/devices/1/edit/") + request.user = AnonymousUser() + return request 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 6f8e586..66cc23c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "netbox-utilities" -version = "0.8.3" +version = "0.8.4" description = "Navigation, tenant utilities, partial-width rack devices, bulk uploads, and rack reordering for NetBox 4.6" readme = "README.md" requires-python = ">=3.12"