fix: expose rack width fields on device edit form
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# NetBox Utilities
|
# NetBox Utilities
|
||||||
|
|
||||||
Plugin für **NetBox 4.6.5** mit neun Funktionen:
|
Plugin für **NetBox 4.6.5 bis 4.6.7** mit neun Funktionen:
|
||||||
|
|
||||||
- Jeder Benutzer kann die Menüs der linken Navigation verschieben oder ausblenden.
|
- Jeder Benutzer kann die Menüs der linken Navigation verschieben oder ausblenden.
|
||||||
- Ein Dropdown in der Kopfleiste setzt einen sitzungsweiten Filter für einen Mandanten oder eine Mandantengruppe.
|
- Ein Dropdown in der Kopfleiste setzt einen sitzungsweiten Filter für einen Mandanten oder eine Mandantengruppe.
|
||||||
@@ -36,7 +36,7 @@ Release-Tag oder ein bestimmter Commit verwendet werden:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
/opt/netbox/venv/bin/pip install --upgrade --force-reinstall \
|
/opt/netbox/venv/bin/pip install --upgrade --force-reinstall \
|
||||||
"git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.8.0"
|
"git+https://git.mrblake.cc/MrBlake/Netbox-Utilities.git@v0.8.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternativ kann hinter dem `@` die vollständige Commit-ID stehen.
|
Alternativ kann hinter dem `@` die vollständige Commit-ID stehen.
|
||||||
@@ -135,8 +135,9 @@ empfohlen.
|
|||||||
|
|
||||||
### Mehrere Geräte nebeneinander in derselben HE
|
### Mehrere Geräte nebeneinander in derselben HE
|
||||||
|
|
||||||
Im normalen NetBox-Geräteformular stehen direkt nach **Rackseite** zwei neue
|
Auf der normalen **Bearbeitungsseite eines Geräts** stehen direkt nach
|
||||||
optionale Felder zur Verfügung:
|
**Rackseite** zwei neue optionale Felder zur Verfügung. Dafür wird kein
|
||||||
|
separates Plugin-Menü benötigt:
|
||||||
|
|
||||||
- **Rackbreite**: volle, halbe, Drittel- oder Viertelbreite;
|
- **Rackbreite**: volle, halbe, Drittel- oder Viertelbreite;
|
||||||
- **Breitenposition**: Position 1 bis 4, von links gezählt.
|
- **Breitenposition**: Position 1 bis 4, von links gezählt.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from netbox.plugins import PluginConfig, get_plugin_config
|
from netbox.plugins import PluginConfig, get_plugin_config
|
||||||
|
|
||||||
__version__ = "0.8.0"
|
__version__ = "0.8.1"
|
||||||
|
|
||||||
|
|
||||||
class NetBoxUtilitiesConfig(PluginConfig):
|
class NetBoxUtilitiesConfig(PluginConfig):
|
||||||
|
|||||||
@@ -306,68 +306,65 @@ def _install_device_validation():
|
|||||||
|
|
||||||
|
|
||||||
def _install_device_form():
|
def _install_device_form():
|
||||||
from dcim.forms import DeviceForm
|
from dcim.views import DeviceEditView
|
||||||
|
|
||||||
if getattr(DeviceForm, "_netbox_utilities_rack_width_installed", False):
|
if getattr(DeviceEditView, "_netbox_utilities_rack_width_installed", False):
|
||||||
return
|
return
|
||||||
|
|
||||||
original_init = DeviceForm.__init__
|
base_device_form = DeviceEditView.form
|
||||||
original_clean = DeviceForm.clean
|
|
||||||
original_save = DeviceForm.save
|
|
||||||
|
|
||||||
@wraps(original_init)
|
class RackWidthDeviceForm(base_device_form):
|
||||||
def width_aware_init(form, *args, **kwargs):
|
utilities_rack_width = forms.ChoiceField(
|
||||||
original_init(form, *args, **kwargs)
|
|
||||||
width, horizontal_position = _stored_width_position(form.instance)
|
|
||||||
form.fields["utilities_rack_width"] = forms.ChoiceField(
|
|
||||||
label="Rackbreite",
|
label="Rackbreite",
|
||||||
choices=WIDTH_CHOICES,
|
choices=WIDTH_CHOICES,
|
||||||
required=False,
|
required=False,
|
||||||
initial=width,
|
initial=FULL_WIDTH,
|
||||||
help_text="Optional: Geräte können sich eine HE nebeneinander teilen.",
|
help_text="Optional: Geräte können sich eine HE nebeneinander teilen.",
|
||||||
)
|
)
|
||||||
form.fields["utilities_horizontal_position"] = forms.ChoiceField(
|
utilities_horizontal_position = forms.ChoiceField(
|
||||||
label="Breitenposition",
|
label="Breitenposition",
|
||||||
choices=POSITION_CHOICES,
|
choices=POSITION_CHOICES,
|
||||||
required=False,
|
required=False,
|
||||||
initial=horizontal_position,
|
initial=1,
|
||||||
help_text="Position von links; bei halber Breite sind Position 1 und 2 möglich.",
|
help_text="Position von links; bei halber Breite sind Position 1 und 2 möglich.",
|
||||||
)
|
)
|
||||||
if not form.is_bound:
|
|
||||||
form.initial["utilities_rack_width"] = width
|
def __init__(self, *args, **kwargs):
|
||||||
form.initial["utilities_horizontal_position"] = horizontal_position
|
super().__init__(*args, **kwargs)
|
||||||
|
width, horizontal_position = _stored_width_position(self.instance)
|
||||||
|
if not self.is_bound:
|
||||||
|
self.initial["utilities_rack_width"] = width
|
||||||
|
self.initial["utilities_horizontal_position"] = horizontal_position
|
||||||
|
|
||||||
reordered = {}
|
reordered = {}
|
||||||
for name, field in form.fields.items():
|
for name, field in self.fields.items():
|
||||||
if name in {"utilities_rack_width", "utilities_horizontal_position"}:
|
if name in {"utilities_rack_width", "utilities_horizontal_position"}:
|
||||||
continue
|
continue
|
||||||
reordered[name] = field
|
reordered[name] = field
|
||||||
if name == "face":
|
if name == "face":
|
||||||
reordered["utilities_rack_width"] = form.fields["utilities_rack_width"]
|
reordered["utilities_rack_width"] = self.fields["utilities_rack_width"]
|
||||||
reordered["utilities_horizontal_position"] = form.fields["utilities_horizontal_position"]
|
reordered["utilities_horizontal_position"] = self.fields["utilities_horizontal_position"]
|
||||||
form.fields = reordered
|
self.fields = reordered
|
||||||
|
|
||||||
@wraps(original_clean)
|
def clean(self):
|
||||||
def width_aware_form_clean(form):
|
cleaned_data = super().clean()
|
||||||
cleaned_data = original_clean(form)
|
|
||||||
try:
|
try:
|
||||||
width, horizontal_position = normalize_width_position(
|
width, horizontal_position = normalize_width_position(
|
||||||
cleaned_data.get("utilities_rack_width"),
|
cleaned_data.get("utilities_rack_width"),
|
||||||
cleaned_data.get("utilities_horizontal_position"),
|
cleaned_data.get("utilities_horizontal_position"),
|
||||||
)
|
)
|
||||||
except ValidationError as error:
|
except ValidationError as error:
|
||||||
form.add_error("utilities_horizontal_position", error)
|
self.add_error("utilities_horizontal_position", error)
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
if not cleaned_data.get("rack") or not cleaned_data.get("position"):
|
if not cleaned_data.get("rack") or not cleaned_data.get("position"):
|
||||||
width, horizontal_position = FULL_WIDTH, 1
|
width, horizontal_position = FULL_WIDTH, 1
|
||||||
cleaned_data["utilities_rack_width"] = width
|
cleaned_data["utilities_rack_width"] = width
|
||||||
cleaned_data["utilities_horizontal_position"] = horizontal_position
|
cleaned_data["utilities_horizontal_position"] = horizontal_position
|
||||||
stage_width_position(form.instance, width, horizontal_position)
|
stage_width_position(self.instance, width, horizontal_position)
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
@wraps(original_save)
|
def save(self, commit=True):
|
||||||
def width_aware_form_save(form, commit=True):
|
device = super().save(commit=commit)
|
||||||
device = original_save(form, commit=commit)
|
|
||||||
if not commit:
|
if not commit:
|
||||||
return device
|
return device
|
||||||
width, horizontal_position = get_width_position(device)
|
width, horizontal_position = get_width_position(device)
|
||||||
@@ -380,10 +377,10 @@ def _install_device_form():
|
|||||||
)
|
)
|
||||||
return device
|
return device
|
||||||
|
|
||||||
DeviceForm.__init__ = width_aware_init
|
RackWidthDeviceForm.__module__ = __name__
|
||||||
DeviceForm.clean = width_aware_form_clean
|
RackWidthDeviceForm.__qualname__ = "RackWidthDeviceForm"
|
||||||
DeviceForm.save = width_aware_form_save
|
DeviceEditView.form = RackWidthDeviceForm
|
||||||
DeviceForm._netbox_utilities_rack_width_installed = True
|
DeviceEditView._netbox_utilities_rack_width_installed = True
|
||||||
|
|
||||||
|
|
||||||
def _install_rack_svg():
|
def _install_rack_svg():
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ from netbox_utilities.rack_width import (
|
|||||||
|
|
||||||
|
|
||||||
class RackWidthTest(SimpleTestCase):
|
class RackWidthTest(SimpleTestCase):
|
||||||
|
def test_device_edit_view_uses_explicit_rack_width_form(self):
|
||||||
|
from dcim.views import DeviceEditView
|
||||||
|
|
||||||
|
self.assertEqual(DeviceEditView.form.__name__, "RackWidthDeviceForm")
|
||||||
|
self.assertIn("utilities_rack_width", DeviceEditView.form.base_fields)
|
||||||
|
self.assertIn("utilities_horizontal_position", DeviceEditView.form.base_fields)
|
||||||
|
|
||||||
def test_normalizes_full_width_to_first_position(self):
|
def test_normalizes_full_width_to_first_position(self):
|
||||||
self.assertEqual(normalize_width_position(1, 4), (1, 1))
|
self.assertEqual(normalize_width_position(1, 4), (1, 1))
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "netbox-utilities"
|
name = "netbox-utilities"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
description = "Navigation, tenant utilities, partial-width rack devices, bulk uploads, and rack reordering for NetBox 4.6"
|
description = "Navigation, tenant utilities, partial-width rack devices, bulk uploads, and rack reordering for NetBox 4.6"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
Reference in New Issue
Block a user