The widgets lacked the form-check-input class, so NetBox's CSS showed them as empty text inputs with no visible checked state. Also pass role PKs as initial value so all device roles in scope are preselected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
84 lines
4.1 KiB
Python
84 lines
4.1 KiB
Python
from django import forms
|
|
from dcim.models import DeviceRole, Location, Site
|
|
from netbox.plugins import get_plugin_config
|
|
from tenancy.models import Tenant, TenantGroup
|
|
from utilities.forms.fields import DynamicModelChoiceField
|
|
|
|
from .branding import get_brandings
|
|
from .sections import DEFAULT_DEVICE_COLUMNS, DEVICE_COLUMNS, SECTIONS
|
|
|
|
FORMAT_CHOICES = (("pdf", "PDF"), ("docx", "Word (.docx)"), ("html", "HTML-Vorschau"))
|
|
|
|
|
|
class ScopeSelectForm(forms.Form):
|
|
site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False, label="Standort")
|
|
location = DynamicModelChoiceField(queryset=Location.objects.all(), required=False, label="Lokation")
|
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, label="Mandant")
|
|
tenantgroup = DynamicModelChoiceField(queryset=TenantGroup.objects.all(), required=False, label="Mandantengruppe")
|
|
|
|
def clean(self):
|
|
data = super().clean()
|
|
chosen = [(k, v) for k, v in data.items() if v]
|
|
if len(chosen) != 1:
|
|
raise forms.ValidationError("Bitte genau einen Scope auswählen.")
|
|
data["kind"], data["obj"] = chosen[0]
|
|
return data
|
|
|
|
|
|
class ExportForm(forms.Form):
|
|
format = forms.ChoiceField(choices=FORMAT_CHOICES, initial="pdf", label="Format")
|
|
title = forms.CharField(max_length=200, label="Titel")
|
|
subtitle = forms.CharField(max_length=200, required=False, label="Untertitel")
|
|
author = forms.CharField(max_length=100, required=False, label="Erstellt von")
|
|
branding = forms.ChoiceField(choices=(), label="Design / Firma")
|
|
|
|
sections = forms.MultipleChoiceField(
|
|
choices=[(s.key, s.label) for s in SECTIONS.values()],
|
|
initial=[s.key for s in SECTIONS.values() if s.default],
|
|
widget=forms.CheckboxSelectMultiple,
|
|
label="Inhalte",
|
|
)
|
|
|
|
roles = forms.ModelMultipleChoiceField(
|
|
queryset=DeviceRole.objects.none(), required=False, widget=forms.CheckboxSelectMultiple, label="Geräterollen"
|
|
)
|
|
device_columns = forms.MultipleChoiceField(
|
|
choices=[(k, v[0]) for k, v in DEVICE_COLUMNS.items()],
|
|
initial=DEFAULT_DEVICE_COLUMNS,
|
|
required=False,
|
|
widget=forms.CheckboxSelectMultiple,
|
|
label="Gerätespalten",
|
|
)
|
|
group_by_site = forms.BooleanField(required=False, initial=True, label="Geräte nach Standort gruppieren")
|
|
|
|
rack_svg = forms.BooleanField(required=False, initial=True, label="Rack-Ansichten (SVG) einbetten")
|
|
rack_faces = forms.MultipleChoiceField(
|
|
choices=(("front", "Vorderseite"), ("rear", "Rückseite")),
|
|
initial=["front"],
|
|
required=False,
|
|
widget=forms.CheckboxSelectMultiple,
|
|
label="Rack-Seiten",
|
|
)
|
|
rack_devices = forms.BooleanField(required=False, initial=True, label="Geräteliste je Rack")
|
|
rack_pagebreak = forms.BooleanField(required=False, initial=True, label="Seitenumbruch nach jedem Rack")
|
|
|
|
include_empty = forms.BooleanField(required=False, label="Leere Abschnitte trotzdem aufführen")
|
|
include_secrets = forms.BooleanField(required=False, label="Geheimnisse (z.B. WLAN-PSK) mit exportieren")
|
|
|
|
def __init__(self, *args, scope=None, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
# Ohne diese Klasse stellt NetBox' CSS die Checkboxen als leere Eingabefelder dar
|
|
for field in self.fields.values():
|
|
if isinstance(field.widget, (forms.CheckboxInput, forms.CheckboxSelectMultiple)):
|
|
field.widget.attrs["class"] = "form-check-input"
|
|
self.fields["branding"].choices = [(k, b["name"]) for k, b in get_brandings().items()]
|
|
if scope is not None:
|
|
role_ids = scope.devices().values("role")
|
|
roles = DeviceRole.objects.filter(pk__in=role_ids).order_by("name")
|
|
self.fields["roles"].queryset = roles
|
|
self.fields["roles"].initial = [r.pk for r in roles]
|
|
self.fields["title"].initial = f"Netzwerkdokumentation {scope.obj}"
|
|
self.fields["subtitle"].initial = f"{scope.label}: {scope.obj}"
|
|
if not get_plugin_config("netbox_customer_export", "allow_secrets"):
|
|
del self.fields["include_secrets"]
|