mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 04:02:52 -06:00
* WIP * WIP * WIP * Make object selector functional * Replace extraneous form fields with selector widgets * Avoid overlap with filterset field names * Show checkmarks next to visibile filters * Update results automatically when searching * Include selector for device/VM component parent fields * Use selector for filtering VLAN group/site * Limit selector to 100 results
This commit is contained in:
parent
2a9178af12
commit
d1f76bec37
@ -1,7 +1,7 @@
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
from dcim.models import Region, Site, SiteGroup
|
from dcim.models import Site
|
||||||
from ipam.models import ASN
|
from ipam.models import ASN
|
||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
@ -114,50 +114,22 @@ class CircuitTerminationForm(NetBoxModelForm):
|
|||||||
'provider_id': '$provider',
|
'provider_id': '$provider',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
},
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
provider_network_provider = DynamicModelChoiceField(
|
|
||||||
queryset=Provider.objects.all(),
|
|
||||||
required=False,
|
required=False,
|
||||||
label='Provider',
|
selector=True
|
||||||
initial_params={
|
|
||||||
'networks': 'provider_network'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
provider_network = DynamicModelChoiceField(
|
provider_network = DynamicModelChoiceField(
|
||||||
queryset=ProviderNetwork.objects.all(),
|
queryset=ProviderNetwork.objects.all(),
|
||||||
query_params={
|
required=False,
|
||||||
'provider_id': '$provider_network_provider',
|
selector=True
|
||||||
},
|
|
||||||
required=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
fields = [
|
fields = [
|
||||||
'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network_provider',
|
'provider', 'circuit', 'term_side', 'site', 'provider_network', 'mark_connected', 'port_speed',
|
||||||
'provider_network', 'mark_connected', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
|
'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags',
|
||||||
'description', 'tags',
|
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'port_speed': SelectSpeedWidget(),
|
'port_speed': SelectSpeedWidget(),
|
||||||
|
@ -14,9 +14,9 @@ from tenancy.forms import TenancyForm
|
|||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
|
APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
|
||||||
DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SelectWithPK,
|
DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SelectWithPK,
|
||||||
SlugField, SelectSpeedWidget,
|
SlugField, SelectSpeedWidget
|
||||||
)
|
)
|
||||||
from virtualization.models import Cluster, ClusterGroup
|
from virtualization.models import Cluster
|
||||||
from wireless.models import WirelessLAN, WirelessLANGroup
|
from wireless.models import WirelessLAN, WirelessLANGroup
|
||||||
from .common import InterfaceCommonForm, ModuleCommonForm
|
from .common import InterfaceCommonForm, ModuleCommonForm
|
||||||
|
|
||||||
@ -157,26 +157,9 @@ class SiteForm(TenancyForm, NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class LocationForm(TenancyForm, NetBoxModelForm):
|
class LocationForm(TenancyForm, NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
parent = DynamicModelChoiceField(
|
parent = DynamicModelChoiceField(
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
@ -188,17 +171,14 @@ class LocationForm(TenancyForm, NetBoxModelForm):
|
|||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Location', (
|
('Location', ('site', 'parent', 'name', 'slug', 'status', 'description', 'tags')),
|
||||||
'region', 'site_group', 'site', 'parent', 'name', 'slug', 'status', 'description', 'tags',
|
|
||||||
)),
|
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Location
|
model = Location
|
||||||
fields = (
|
fields = (
|
||||||
'region', 'site_group', 'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant',
|
'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'tags',
|
||||||
'tags',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -219,26 +199,9 @@ class RackRoleForm(NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class RackForm(TenancyForm, NetBoxModelForm):
|
class RackForm(TenancyForm, NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
location = DynamicModelChoiceField(
|
location = DynamicModelChoiceField(
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
@ -256,48 +219,16 @@ class RackForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status',
|
'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial',
|
||||||
'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
|
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
||||||
'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags',
|
'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RackReservationForm(TenancyForm, NetBoxModelForm):
|
class RackReservationForm(TenancyForm, NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
location = DynamicModelChoiceField(
|
|
||||||
queryset=Location.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
rack = DynamicModelChoiceField(
|
rack = DynamicModelChoiceField(
|
||||||
queryset=Rack.objects.all(),
|
queryset=Rack.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'site_id': '$site',
|
|
||||||
'location_id': '$location',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
units = NumericArrayField(
|
units = NumericArrayField(
|
||||||
base_field=forms.IntegerField(),
|
base_field=forms.IntegerField(),
|
||||||
@ -311,15 +242,14 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Reservation', ('region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')),
|
('Reservation', ('rack', 'units', 'user', 'description', 'tags')),
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'tenant_group', 'tenant',
|
'rack', 'units', 'user', 'tenant_group', 'tenant', 'description', 'comments', 'tags',
|
||||||
'description', 'comments', 'tags',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -441,26 +371,9 @@ class PlatformForm(NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class DeviceForm(TenancyForm, NetBoxModelForm):
|
class DeviceForm(TenancyForm, NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
location = DynamicModelChoiceField(
|
location = DynamicModelChoiceField(
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
@ -491,43 +404,21 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
manufacturer = DynamicModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'device_types': '$device_type'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
device_type = DynamicModelChoiceField(
|
device_type = DynamicModelChoiceField(
|
||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'manufacturer_id': '$manufacturer'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
device_role = DynamicModelChoiceField(
|
device_role = DynamicModelChoiceField(
|
||||||
queryset=DeviceRole.objects.all()
|
queryset=DeviceRole.objects.all()
|
||||||
)
|
)
|
||||||
platform = DynamicModelChoiceField(
|
platform = DynamicModelChoiceField(
|
||||||
queryset=Platform.objects.all(),
|
queryset=Platform.objects.all(),
|
||||||
required=False,
|
required=False
|
||||||
query_params={
|
|
||||||
'manufacturer_id': ['$manufacturer', 'null']
|
|
||||||
}
|
|
||||||
)
|
|
||||||
cluster_group = DynamicModelChoiceField(
|
|
||||||
queryset=ClusterGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
null_option='None',
|
|
||||||
initial_params={
|
|
||||||
'clusters': '$cluster'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
cluster = DynamicModelChoiceField(
|
cluster = DynamicModelChoiceField(
|
||||||
queryset=Cluster.objects.all(),
|
queryset=Cluster.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True
|
||||||
'group_id': '$cluster_group'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
local_context_data = JSONField(
|
local_context_data = JSONField(
|
||||||
@ -536,7 +427,8 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
)
|
)
|
||||||
virtual_chassis = DynamicModelChoiceField(
|
virtual_chassis = DynamicModelChoiceField(
|
||||||
queryset=VirtualChassis.objects.all(),
|
queryset=VirtualChassis.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
vc_position = forms.IntegerField(
|
vc_position = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -556,10 +448,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack',
|
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'site', 'rack', 'location', 'position', 'face',
|
||||||
'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6',
|
'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6', 'cluster', 'tenant_group', 'tenant',
|
||||||
'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority',
|
'virtual_chassis', 'vc_position', 'vc_priority', 'description', 'config_template', 'comments', 'tags',
|
||||||
'description', 'config_template', 'comments', 'tags', 'local_context_data'
|
'local_context_data'
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -632,18 +524,9 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
|
|||||||
'device_id': '$device'
|
'device_id': '$device'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
manufacturer = DynamicModelChoiceField(
|
|
||||||
queryset=Manufacturer.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'module_types': '$module_type'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
module_type = DynamicModelChoiceField(
|
module_type = DynamicModelChoiceField(
|
||||||
queryset=ModuleType.objects.all(),
|
queryset=ModuleType.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'manufacturer_id': '$manufacturer'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
replicate_components = forms.BooleanField(
|
replicate_components = forms.BooleanField(
|
||||||
@ -651,7 +534,6 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
|
|||||||
initial=True,
|
initial=True,
|
||||||
help_text=_("Automatically populate components associated with this module type")
|
help_text=_("Automatically populate components associated with this module type")
|
||||||
)
|
)
|
||||||
|
|
||||||
adopt_components = forms.BooleanField(
|
adopt_components = forms.BooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
initial=False,
|
initial=False,
|
||||||
@ -659,9 +541,7 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Module', (
|
('Module', ('device', 'module_bay', 'module_type', 'status', 'description', 'tags')),
|
||||||
'device', 'module_bay', 'manufacturer', 'module_type', 'status', 'description', 'tags',
|
|
||||||
)),
|
|
||||||
('Hardware', (
|
('Hardware', (
|
||||||
'serial', 'asset_tag', 'replicate_components', 'adopt_components',
|
'serial', 'asset_tag', 'replicate_components', 'adopt_components',
|
||||||
)),
|
)),
|
||||||
@ -670,8 +550,8 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Module
|
model = Module
|
||||||
fields = [
|
fields = [
|
||||||
'device', 'module_bay', 'manufacturer', 'module_type', 'status', 'serial', 'asset_tag', 'tags',
|
'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag', 'tags', 'replicate_components',
|
||||||
'replicate_components', 'adopt_components', 'description', 'comments',
|
'adopt_components', 'description', 'comments',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -702,26 +582,9 @@ class CableForm(TenancyForm, NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class PowerPanelForm(NetBoxModelForm):
|
class PowerPanelForm(NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
location = DynamicModelChoiceField(
|
location = DynamicModelChoiceField(
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
@ -733,80 +596,38 @@ class PowerPanelForm(NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'description', 'tags')),
|
('Power Panel', ('site', 'location', 'name', 'description', 'tags')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'name', 'description', 'comments', 'tags',
|
'site', 'location', 'name', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class PowerFeedForm(NetBoxModelForm):
|
class PowerFeedForm(NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites__powerpanel': '$power_panel'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'powerpanel': '$power_panel'
|
|
||||||
},
|
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
power_panel = DynamicModelChoiceField(
|
power_panel = DynamicModelChoiceField(
|
||||||
queryset=PowerPanel.objects.all(),
|
queryset=PowerPanel.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'site_id': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
location = DynamicModelChoiceField(
|
|
||||||
queryset=Location.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site'
|
|
||||||
},
|
|
||||||
initial_params={
|
|
||||||
'racks': '$rack'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
rack = DynamicModelChoiceField(
|
rack = DynamicModelChoiceField(
|
||||||
queryset=Rack.objects.all(),
|
queryset=Rack.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True
|
||||||
'location_id': '$location',
|
|
||||||
'site_id': '$site'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Power Panel', ('region', 'site', 'power_panel')),
|
('Power Feed', ('power_panel', 'rack', 'name', 'status', 'type', 'description', 'mark_connected', 'tags')),
|
||||||
('Power Feed', ('location', 'rack', 'name', 'status', 'type', 'description', 'mark_connected', 'tags')),
|
|
||||||
('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')),
|
('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type',
|
'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
|
||||||
'mark_connected', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', 'description', 'comments',
|
'max_utilization', 'description', 'comments', 'tags',
|
||||||
'tags',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -878,43 +699,12 @@ class DeviceVCMembershipForm(forms.ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class VCMemberSelectForm(BootstrapMixin, forms.Form):
|
class VCMemberSelectForm(BootstrapMixin, forms.Form):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
rack = DynamicModelChoiceField(
|
|
||||||
queryset=Rack.objects.all(),
|
|
||||||
required=False,
|
|
||||||
null_option='None',
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
query_params={
|
query_params={
|
||||||
'site_id': '$site',
|
|
||||||
'rack_id': '$rack',
|
|
||||||
'virtual_chassis_id': 'null',
|
'virtual_chassis_id': 'null',
|
||||||
}
|
},
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean_device(self):
|
def clean_device(self):
|
||||||
@ -1150,7 +940,8 @@ class InventoryItemTemplateForm(ComponentTemplateForm):
|
|||||||
|
|
||||||
class DeviceComponentForm(NetBoxModelForm):
|
class DeviceComponentForm(NetBoxModelForm):
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all()
|
queryset=Device.objects.all(),
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -1592,53 +1383,9 @@ class InventoryItemRoleForm(NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
|
class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
location = DynamicModelChoiceField(
|
|
||||||
queryset=Location.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site'
|
|
||||||
},
|
|
||||||
initial_params={
|
|
||||||
'racks': '$rack'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
rack = DynamicModelChoiceField(
|
|
||||||
queryset=Rack.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site',
|
|
||||||
'location_id': '$location',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
query_params={
|
selector=True
|
||||||
'site_id': '$site',
|
|
||||||
'location_id': '$location',
|
|
||||||
'rack_id': '$rack',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
primary_ip4 = DynamicModelChoiceField(
|
primary_ip4 = DynamicModelChoiceField(
|
||||||
queryset=IPAddress.objects.all(),
|
queryset=IPAddress.objects.all(),
|
||||||
@ -1660,14 +1407,13 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Assigned Device', ('region', 'site_group', 'site', 'location', 'rack', 'device')),
|
('Virtual Device Context', ('device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tags')),
|
||||||
('Virtual Device Context', ('name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tags')),
|
|
||||||
('Tenancy', ('tenant_group', 'tenant'))
|
('Tenancy', ('tenant_group', 'tenant'))
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualDeviceContext
|
model = VirtualDeviceContext
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'rack', 'device', 'name', 'status', 'identifier',
|
'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant',
|
||||||
'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'comments', 'tags'
|
'comments', 'tags'
|
||||||
]
|
]
|
||||||
|
@ -200,40 +200,11 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('VRF')
|
label=_('VRF')
|
||||||
)
|
)
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
null_option='None',
|
selector=True,
|
||||||
query_params={
|
null_option='None'
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
vlan_group = DynamicModelChoiceField(
|
|
||||||
queryset=VLANGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('VLAN group'),
|
|
||||||
null_option='None',
|
|
||||||
query_params={
|
|
||||||
'site': '$site'
|
|
||||||
},
|
|
||||||
initial_params={
|
|
||||||
'vlans': '$vlan'
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
vlan = DynamicModelChoiceField(
|
vlan = DynamicModelChoiceField(
|
||||||
queryset=VLAN.objects.all(),
|
queryset=VLAN.objects.all(),
|
||||||
@ -241,7 +212,6 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
|
|||||||
label=_('VLAN'),
|
label=_('VLAN'),
|
||||||
query_params={
|
query_params={
|
||||||
'site_id': '$site',
|
'site_id': '$site',
|
||||||
'group_id': '$vlan_group',
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
role = DynamicModelChoiceField(
|
role = DynamicModelChoiceField(
|
||||||
@ -252,7 +222,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
|
|||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')),
|
('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')),
|
||||||
('Site/VLAN Assignment', ('region', 'site_group', 'site', 'vlan_group', 'vlan')),
|
('Site/VLAN Assignment', ('site', 'vlan')),
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -329,65 +299,22 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('VRF')
|
label=_('VRF')
|
||||||
)
|
)
|
||||||
nat_region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Region'),
|
|
||||||
initial_params={
|
|
||||||
'sites': '$nat_site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
nat_site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Site group'),
|
|
||||||
initial_params={
|
|
||||||
'sites': '$nat_site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
nat_site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Site'),
|
|
||||||
query_params={
|
|
||||||
'region_id': '$nat_region',
|
|
||||||
'group_id': '$nat_site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
nat_rack = DynamicModelChoiceField(
|
|
||||||
queryset=Rack.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Rack'),
|
|
||||||
null_option='None',
|
|
||||||
query_params={
|
|
||||||
'site_id': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
nat_device = DynamicModelChoiceField(
|
nat_device = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_('Device'),
|
selector=True,
|
||||||
query_params={
|
label=_('Device')
|
||||||
'site_id': '$site',
|
|
||||||
'rack_id': '$nat_rack',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
nat_cluster = DynamicModelChoiceField(
|
|
||||||
queryset=Cluster.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Cluster')
|
|
||||||
)
|
)
|
||||||
nat_virtual_machine = DynamicModelChoiceField(
|
nat_virtual_machine = DynamicModelChoiceField(
|
||||||
queryset=VirtualMachine.objects.all(),
|
queryset=VirtualMachine.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_('Virtual Machine'),
|
selector=True,
|
||||||
query_params={
|
label=_('Virtual Machine')
|
||||||
'cluster_id': '$nat_cluster',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
nat_vrf = DynamicModelChoiceField(
|
nat_vrf = DynamicModelChoiceField(
|
||||||
queryset=VRF.objects.all(),
|
queryset=VRF.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
|
selector=True,
|
||||||
label=_('VRF')
|
label=_('VRF')
|
||||||
)
|
)
|
||||||
nat_inside = DynamicModelChoiceField(
|
nat_inside = DynamicModelChoiceField(
|
||||||
@ -409,9 +336,8 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = [
|
fields = [
|
||||||
'address', 'vrf', 'status', 'role', 'dns_name', 'primary_for_parent', 'nat_site', 'nat_rack', 'nat_device',
|
'address', 'vrf', 'status', 'role', 'dns_name', 'primary_for_parent', 'nat_device', 'nat_virtual_machine',
|
||||||
'nat_cluster', 'nat_virtual_machine', 'nat_vrf', 'nat_inside', 'tenant_group', 'tenant', 'description',
|
'nat_vrf', 'nat_inside', 'tenant_group', 'tenant', 'description', 'comments', 'tags',
|
||||||
'comments', 'tags',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -714,58 +640,18 @@ class VLANGroupForm(NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class VLANForm(TenancyForm, NetBoxModelForm):
|
class VLANForm(TenancyForm, NetBoxModelForm):
|
||||||
# VLANGroup assignment fields
|
|
||||||
scope_type = forms.ChoiceField(
|
|
||||||
choices=(
|
|
||||||
('', ''),
|
|
||||||
('dcim.region', 'Region'),
|
|
||||||
('dcim.sitegroup', 'Site group'),
|
|
||||||
('dcim.site', 'Site'),
|
|
||||||
('dcim.location', 'Location'),
|
|
||||||
('dcim.rack', 'Rack'),
|
|
||||||
('virtualization.clustergroup', 'Cluster group'),
|
|
||||||
('virtualization.cluster', 'Cluster'),
|
|
||||||
),
|
|
||||||
required=False,
|
|
||||||
label=_('Group scope')
|
|
||||||
)
|
|
||||||
group = DynamicModelChoiceField(
|
group = DynamicModelChoiceField(
|
||||||
queryset=VLANGroup.objects.all(),
|
queryset=VLANGroup.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True,
|
||||||
'scope_type': '$scope_type',
|
|
||||||
},
|
|
||||||
label=_('VLAN Group')
|
label=_('VLAN Group')
|
||||||
)
|
)
|
||||||
|
|
||||||
# Site assignment fields
|
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
},
|
|
||||||
label=_('Region')
|
|
||||||
)
|
|
||||||
sitegroup = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
},
|
|
||||||
label=_('Site group')
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
null_option='None',
|
null_option='None',
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$sitegroup',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Other fields
|
|
||||||
role = DynamicModelChoiceField(
|
role = DynamicModelChoiceField(
|
||||||
queryset=Role.objects.all(),
|
queryset=Role.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
@ -804,11 +690,13 @@ class ServiceTemplateForm(NetBoxModelForm):
|
|||||||
class ServiceForm(NetBoxModelForm):
|
class ServiceForm(NetBoxModelForm):
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
virtual_machine = DynamicModelChoiceField(
|
virtual_machine = DynamicModelChoiceField(
|
||||||
queryset=VirtualMachine.objects.all(),
|
queryset=VirtualMachine.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
ports = NumericArrayField(
|
ports = NumericArrayField(
|
||||||
base_field=forms.IntegerField(
|
base_field=forms.IntegerField(
|
||||||
@ -908,43 +796,21 @@ class L2VPNTerminationForm(NetBoxModelForm):
|
|||||||
label=_('L2VPN'),
|
label=_('L2VPN'),
|
||||||
fetch_trigger='open'
|
fetch_trigger='open'
|
||||||
)
|
)
|
||||||
device_vlan = DynamicModelChoiceField(
|
|
||||||
queryset=Device.objects.all(),
|
|
||||||
label=_("Available on Device"),
|
|
||||||
required=False,
|
|
||||||
query_params={}
|
|
||||||
)
|
|
||||||
vlan = DynamicModelChoiceField(
|
vlan = DynamicModelChoiceField(
|
||||||
queryset=VLAN.objects.all(),
|
queryset=VLAN.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True,
|
||||||
'available_on_device': '$device_vlan'
|
|
||||||
},
|
|
||||||
label=_('VLAN')
|
label=_('VLAN')
|
||||||
)
|
)
|
||||||
device = DynamicModelChoiceField(
|
|
||||||
queryset=Device.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={}
|
|
||||||
)
|
|
||||||
interface = DynamicModelChoiceField(
|
interface = DynamicModelChoiceField(
|
||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True
|
||||||
'device_id': '$device'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
virtual_machine = DynamicModelChoiceField(
|
|
||||||
queryset=VirtualMachine.objects.all(),
|
|
||||||
required=False,
|
|
||||||
query_params={}
|
|
||||||
)
|
)
|
||||||
vminterface = DynamicModelChoiceField(
|
vminterface = DynamicModelChoiceField(
|
||||||
queryset=VMInterface.objects.all(),
|
queryset=VMInterface.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True,
|
||||||
'virtual_machine_id': '$virtual_machine'
|
|
||||||
},
|
|
||||||
label=_('Interface')
|
label=_('Interface')
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -958,7 +824,6 @@ class L2VPNTerminationForm(NetBoxModelForm):
|
|||||||
|
|
||||||
if instance:
|
if instance:
|
||||||
if type(instance.assigned_object) is Interface:
|
if type(instance.assigned_object) is Interface:
|
||||||
initial['device'] = instance.assigned_object.parent
|
|
||||||
initial['interface'] = instance.assigned_object
|
initial['interface'] = instance.assigned_object
|
||||||
elif type(instance.assigned_object) is VLAN:
|
elif type(instance.assigned_object) is VLAN:
|
||||||
initial['vlan'] = instance.assigned_object
|
initial['vlan'] = instance.assigned_object
|
||||||
|
@ -10,7 +10,7 @@ from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_a
|
|||||||
from netbox.api.views import APIRootView, StatusView
|
from netbox.api.views import APIRootView, StatusView
|
||||||
from netbox.graphql.schema import schema
|
from netbox.graphql.schema import schema
|
||||||
from netbox.graphql.views import GraphQLView
|
from netbox.graphql.views import GraphQLView
|
||||||
from netbox.views import HomeView, StaticMediaFailureView, SearchView
|
from netbox.views import HomeView, StaticMediaFailureView, SearchView, htmx
|
||||||
from users.views import LoginView, LogoutView
|
from users.views import LoginView, LogoutView
|
||||||
from .admin import admin_site
|
from .admin import admin_site
|
||||||
|
|
||||||
@ -51,6 +51,9 @@ _patterns = [
|
|||||||
path('virtualization/', include('virtualization.urls')),
|
path('virtualization/', include('virtualization.urls')),
|
||||||
path('wireless/', include('wireless.urls')),
|
path('wireless/', include('wireless.urls')),
|
||||||
|
|
||||||
|
# HTMX views
|
||||||
|
path('htmx/object-selector/', htmx.ObjectSelectorView.as_view(), name='htmx_object_selector'),
|
||||||
|
|
||||||
# API
|
# API
|
||||||
path('api/', APIRootView.as_view(), name='api-root'),
|
path('api/', APIRootView.as_view(), name='api-root'),
|
||||||
path('api/circuits/', include('circuits.api.urls')),
|
path('api/circuits/', include('circuits.api.urls')),
|
||||||
|
56
netbox/netbox/views/htmx.py
Normal file
56
netbox/netbox/views/htmx.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.http import Http404
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
from django.views.generic import View
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectSelectorView(View):
|
||||||
|
template_name = 'htmx/object_selector.html'
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
model = self._get_model(request.GET.get('_model', ''))
|
||||||
|
|
||||||
|
form_class = self._get_form_class(model)
|
||||||
|
form = form_class(request.GET)
|
||||||
|
|
||||||
|
if '_search' in request.GET:
|
||||||
|
# Return only search results
|
||||||
|
filterset = self._get_filterset_class(model)
|
||||||
|
|
||||||
|
queryset = model.objects.restrict(request.user)
|
||||||
|
if filterset:
|
||||||
|
queryset = filterset(request.GET, queryset, request=request).qs
|
||||||
|
|
||||||
|
return render(request, 'htmx/object_selector_results.html', {
|
||||||
|
'results': queryset[:100],
|
||||||
|
})
|
||||||
|
|
||||||
|
return render(request, self.template_name, {
|
||||||
|
'form': form,
|
||||||
|
'model': model,
|
||||||
|
'target_id': request.GET.get('target'),
|
||||||
|
})
|
||||||
|
|
||||||
|
def _get_model(self, label):
|
||||||
|
try:
|
||||||
|
app_label, model_name = label.split('.')
|
||||||
|
content_type = ContentType.objects.get_by_natural_key(app_label, model_name)
|
||||||
|
except (ValueError, ObjectDoesNotExist):
|
||||||
|
raise Http404
|
||||||
|
return content_type.model_class()
|
||||||
|
|
||||||
|
def _get_form_class(self, model):
|
||||||
|
if hasattr(self, 'form_class'):
|
||||||
|
return self.form_class
|
||||||
|
app_label = model._meta.app_label
|
||||||
|
class_name = f'{model.__name__}FilterForm'
|
||||||
|
return import_string(f'{app_label}.forms.{class_name}')
|
||||||
|
|
||||||
|
def _get_filterset_class(self, model):
|
||||||
|
if hasattr(self, 'filterset_class'):
|
||||||
|
return self.filterset_class
|
||||||
|
app_label = model._meta.app_label
|
||||||
|
class_name = f'{model.__name__}FilterSet'
|
||||||
|
return import_string(f'{app_label}.filtersets.{class_name}')
|
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
@ -1,9 +1,10 @@
|
|||||||
import { getElements, isTruthy } from './util';
|
import { getElements, isTruthy } from './util';
|
||||||
import { initButtons } from './buttons';
|
import { initButtons } from './buttons';
|
||||||
import { initSelect } from './select';
|
import { initSelect } from './select';
|
||||||
|
import { initObjectSelector } from './objectSelector';
|
||||||
|
|
||||||
function initDepedencies(): void {
|
function initDepedencies(): void {
|
||||||
for (const init of [initButtons, initSelect]) {
|
for (const init of [initButtons, initSelect, initObjectSelector]) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
netbox/project-static/src/objectSelector.ts
Normal file
32
netbox/project-static/src/objectSelector.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { getElements } from './util';
|
||||||
|
|
||||||
|
function handleSelection(link: HTMLAnchorElement): void {
|
||||||
|
const selector_results = document.getElementById('selector_results');
|
||||||
|
if (selector_results == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const target_id = selector_results.getAttribute('data-selector-target');
|
||||||
|
if (target_id == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const target = document.getElementById(target_id);
|
||||||
|
if (target == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = link.getAttribute('data-label');
|
||||||
|
const value = link.getAttribute('data-value');
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
target.slim.setData([
|
||||||
|
{text: label, value: value}
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function initObjectSelector(): void {
|
||||||
|
for (const element of getElements<HTMLAnchorElement>('#selector_results a')) {
|
||||||
|
element.addEventListener('click', () => handleSelection(element));
|
||||||
|
}
|
||||||
|
}
|
@ -27,12 +27,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="tab-content p-0 border-0">
|
<div class="tab-content p-0 border-0">
|
||||||
<div class="tab-pane{% if not providernetwork_tab_active %} active{% endif %}" id="site">
|
<div class="tab-pane{% if not providernetwork_tab_active %} active{% endif %}" id="site">
|
||||||
{% render_field form.region %}
|
|
||||||
{% render_field form.site_group %}
|
|
||||||
{% render_field form.site %}
|
{% render_field form.site %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane{% if providernetwork_tab_active %} active{% endif %}" id="providernetwork">
|
<div class="tab-pane{% if providernetwork_tab_active %} active{% endif %}" id="providernetwork">
|
||||||
{% render_field form.provider_network_provider %}
|
|
||||||
{% render_field form.provider_network %}
|
{% render_field form.provider_network %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<h5 class="offset-sm-3">Hardware</h5>
|
<h5 class="offset-sm-3">Hardware</h5>
|
||||||
</div>
|
</div>
|
||||||
{% render_field form.manufacturer %}
|
|
||||||
{% render_field form.device_type %}
|
{% render_field form.device_type %}
|
||||||
{% render_field form.airflow %}
|
{% render_field form.airflow %}
|
||||||
{% render_field form.serial %}
|
{% render_field form.serial %}
|
||||||
@ -29,8 +28,6 @@
|
|||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<h5 class="offset-sm-3">Location</h5>
|
<h5 class="offset-sm-3">Location</h5>
|
||||||
</div>
|
</div>
|
||||||
{% render_field form.region %}
|
|
||||||
{% render_field form.site_group %}
|
|
||||||
{% render_field form.site %}
|
{% render_field form.site %}
|
||||||
{% render_field form.location %}
|
{% render_field form.location %}
|
||||||
{% render_field form.rack %}
|
{% render_field form.rack %}
|
||||||
@ -76,7 +73,6 @@
|
|||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<h5 class="offset-sm-3">Virtualization</h5>
|
<h5 class="offset-sm-3">Virtualization</h5>
|
||||||
</div>
|
</div>
|
||||||
{% render_field form.cluster_group %}
|
|
||||||
{% render_field form.cluster %}
|
{% render_field form.cluster %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<h5 class="offset-sm-3">Rack</h5>
|
<h5 class="offset-sm-3">Rack</h5>
|
||||||
</div>
|
</div>
|
||||||
{% render_field form.region %}
|
|
||||||
{% render_field form.site_group %}
|
|
||||||
{% render_field form.site %}
|
{% render_field form.site %}
|
||||||
{% render_field form.location %}
|
{% render_field form.location %}
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
|
@ -74,3 +74,7 @@ Context:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock content-wrapper %}
|
{% endblock content-wrapper %}
|
||||||
|
|
||||||
|
{% block modals %}
|
||||||
|
{% include 'inc/htmx_modal.html' with size='lg' %}
|
||||||
|
{% endblock %}
|
||||||
|
32
netbox/templates/htmx/object_selector.html
Normal file
32
netbox/templates/htmx/object_selector.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{% load form_helpers %}
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Select {{ model|meta:"verbose_name"|bettertitle }}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body row">
|
||||||
|
<div class="col-3">
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
{% for field in form.visible_fields %}
|
||||||
|
<a href="#" class="list-group-item list-group-item-action px-0 py-1" data-bs-toggle="collapse" data-bs-target="#checkmark{{ forloop.counter }}, #selector{{ forloop.counter }}">
|
||||||
|
<span id="checkmark{{ forloop.counter }}" class="collapse{% if forloop.counter < 3 %} show{% endif %}"><i class="mdi mdi-check-bold"></i></span>
|
||||||
|
{{ field.label }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-9">
|
||||||
|
<form hx-get="{% url 'htmx_object_selector' %}?_model={{ model|meta:"label_lower" }}" hx-target="#selector_results" hx-trigger="load, submit, keyup from:#id_q delay:500ms">
|
||||||
|
<input type="hidden" name="_search" value="true" />
|
||||||
|
<div class="tab-content p-1">
|
||||||
|
{% for field in form.visible_fields %}
|
||||||
|
<div class="collapse{% if forloop.counter < 3 %} show{% endif %}" id="selector{{ forloop.counter }}">{% render_field field %}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="text-end">
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary">Search</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="selector_results" class="mt-3" data-selector-target="{{ target_id }}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
13
netbox/templates/htmx/object_selector_results.html
Normal file
13
netbox/templates/htmx/object_selector_results.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<div class="list-group">
|
||||||
|
{% for object in results %}
|
||||||
|
<a href="#" class="list-group-item list-group-item-action" data-label="{{ object }}" data-value="{{ object.pk }}" data-bs-dismiss="modal">
|
||||||
|
<h6 class="mb-1">
|
||||||
|
{{ object }}
|
||||||
|
{% if object.status %}{% badge object.get_status_display bg_color=object.get_status_color %}{% endif %}
|
||||||
|
</h6>
|
||||||
|
{% if object.description %}
|
||||||
|
<small>{{ object.description }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
@ -1,5 +1,5 @@
|
|||||||
<div class="modal fade" id="htmx-modal" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="htmx-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog{% if size %} modal-{{ size }}{% endif %}">
|
||||||
<div class="modal-content" id="htmx-modal-content">
|
<div class="modal-content" id="htmx-modal-content">
|
||||||
{# Dynamic content goes here #}
|
{# Dynamic content goes here #}
|
||||||
</div>
|
</div>
|
||||||
|
@ -121,14 +121,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="tab-content p-0 border-0">
|
<div class="tab-content p-0 border-0">
|
||||||
<div class="tab-pane active" id="by_device" aria-labelledby="device_tab" role="tabpanel">
|
<div class="tab-pane active" id="by_device" aria-labelledby="device_tab" role="tabpanel">
|
||||||
{% render_field form.nat_region %}
|
|
||||||
{% render_field form.nat_site_group %}
|
|
||||||
{% render_field form.nat_site %}
|
|
||||||
{% render_field form.nat_rack %}
|
|
||||||
{% render_field form.nat_device %}
|
{% render_field form.nat_device %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="by_vm" aria-labelledby="vm_tab" role="tabpanel">
|
<div class="tab-pane" id="by_vm" aria-labelledby="vm_tab" role="tabpanel">
|
||||||
{% render_field form.nat_cluster %}
|
|
||||||
{% render_field form.nat_virtual_machine %}
|
{% render_field form.nat_virtual_machine %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="by_vrf" aria-labelledby="vrf_tab" role="tabpanel">
|
<div class="tab-pane" id="by_vrf" aria-labelledby="vrf_tab" role="tabpanel">
|
||||||
|
@ -32,15 +32,12 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="tab-content p-0 border-0">
|
<div class="tab-content p-0 border-0">
|
||||||
<div class="tab-pane {% if not form.initial.interface or form.initial.vminterface %}active{% endif %}" id="vlan" role="tabpanel" aria-labeled-by="vlan_tab">
|
<div class="tab-pane {% if not form.initial.interface or form.initial.vminterface %}active{% endif %}" id="vlan" role="tabpanel" aria-labeled-by="vlan_tab">
|
||||||
{% render_field form.device_vlan %}
|
|
||||||
{% render_field form.vlan %}
|
{% render_field form.vlan %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane {% if form.initial.interface %}active{% endif %}" id="interface" role="tabpanel" aria-labeled-by="interface_tab">
|
<div class="tab-pane {% if form.initial.interface %}active{% endif %}" id="interface" role="tabpanel" aria-labeled-by="interface_tab">
|
||||||
{% render_field form.device %}
|
|
||||||
{% render_field form.interface %}
|
{% render_field form.interface %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane {% if form.initial.vminterface %}active{% endif %}" id="vminterface" role="tabpanel" aria-labeled-by="vminterface_tab">
|
<div class="tab-pane {% if form.initial.vminterface %}active{% endif %}" id="vminterface" role="tabpanel" aria-labeled-by="vminterface_tab">
|
||||||
{% render_field form.virtual_machine %}
|
|
||||||
{% render_field form.vminterface %}
|
{% render_field form.vminterface %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,12 +43,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="tab-content p-0 border-0">
|
<div class="tab-content p-0 border-0">
|
||||||
<div class="tab-pane{% if not site_tab_active %} active{% endif %}" id="group">
|
<div class="tab-pane{% if not site_tab_active %} active{% endif %}" id="group">
|
||||||
{% render_field form.scope_type %}
|
|
||||||
{% render_field form.group %}
|
{% render_field form.group %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane{% if site_tab_active %} active{% endif %}" id="site">
|
<div class="tab-pane{% if site_tab_active %} active{% endif %}" id="site">
|
||||||
{% render_field form.region %}
|
|
||||||
{% render_field form.sitegroup %}
|
|
||||||
{% render_field form.site %}
|
{% render_field form.site %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,24 +26,38 @@ class DynamicModelChoiceMixin:
|
|||||||
choice (optional)
|
choice (optional)
|
||||||
fetch_trigger: The event type which will cause the select element to
|
fetch_trigger: The event type which will cause the select element to
|
||||||
fetch data from the API. Must be 'load', 'open', or 'collapse'. (optional)
|
fetch data from the API. Must be 'load', 'open', or 'collapse'. (optional)
|
||||||
|
selector: Include an advanced object selection widget to assist the user in identifying the desired object
|
||||||
"""
|
"""
|
||||||
filter = django_filters.ModelChoiceFilter
|
filter = django_filters.ModelChoiceFilter
|
||||||
widget = widgets.APISelect
|
widget = widgets.APISelect
|
||||||
|
|
||||||
def __init__(self, query_params=None, initial_params=None, null_option=None, disabled_indicator=None,
|
def __init__(
|
||||||
fetch_trigger=None, empty_label=None, *args, **kwargs):
|
self,
|
||||||
|
queryset,
|
||||||
|
*,
|
||||||
|
query_params=None,
|
||||||
|
initial_params=None,
|
||||||
|
null_option=None,
|
||||||
|
disabled_indicator=None,
|
||||||
|
fetch_trigger=None,
|
||||||
|
empty_label=None,
|
||||||
|
selector=False,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
self.model = queryset.model
|
||||||
self.query_params = query_params or {}
|
self.query_params = query_params or {}
|
||||||
self.initial_params = initial_params or {}
|
self.initial_params = initial_params or {}
|
||||||
self.null_option = null_option
|
self.null_option = null_option
|
||||||
self.disabled_indicator = disabled_indicator
|
self.disabled_indicator = disabled_indicator
|
||||||
self.fetch_trigger = fetch_trigger
|
self.fetch_trigger = fetch_trigger
|
||||||
|
self.selector = selector
|
||||||
|
|
||||||
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
|
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
|
||||||
# by widget_attrs()
|
# by widget_attrs()
|
||||||
self.to_field_name = kwargs.get('to_field_name')
|
self.to_field_name = kwargs.get('to_field_name')
|
||||||
self.empty_option = empty_label or ""
|
self.empty_option = empty_label or ""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(queryset, **kwargs)
|
||||||
|
|
||||||
def widget_attrs(self, widget):
|
def widget_attrs(self, widget):
|
||||||
attrs = {
|
attrs = {
|
||||||
@ -70,6 +84,10 @@ class DynamicModelChoiceMixin:
|
|||||||
if (len(self.query_params) > 0):
|
if (len(self.query_params) > 0):
|
||||||
widget.add_query_params(self.query_params)
|
widget.add_query_params(self.query_params)
|
||||||
|
|
||||||
|
# Include object selector?
|
||||||
|
if self.selector:
|
||||||
|
attrs['selector'] = self.model._meta.label_lower
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def get_bound_field(self, form, field_name):
|
def get_bound_field(self, form, field_name):
|
||||||
|
@ -121,6 +121,7 @@ class APISelect(forms.Select):
|
|||||||
|
|
||||||
:param api_url: API endpoint URL. Required if not set automatically by the parent field.
|
:param api_url: API endpoint URL. Required if not set automatically by the parent field.
|
||||||
"""
|
"""
|
||||||
|
template_name = 'widgets/apiselect.html'
|
||||||
option_template_name = 'widgets/select_option.html'
|
option_template_name = 'widgets/select_option.html'
|
||||||
dynamic_params: Dict[str, str]
|
dynamic_params: Dict[str, str]
|
||||||
static_params: Dict[str, List[str]]
|
static_params: Dict[str, List[str]]
|
||||||
|
18
netbox/utilities/templates/widgets/apiselect.html
Normal file
18
netbox/utilities/templates/widgets/apiselect.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% if widget.attrs.selector %}
|
||||||
|
<div class="d-flex">
|
||||||
|
{% include 'django/forms/widgets/select.html' %}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title="Open selector"
|
||||||
|
class="btn btn-sm btn-outline-dark border-input ms-1"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#htmx-modal"
|
||||||
|
hx-get="{% url 'htmx_object_selector' %}?_model={{ widget.attrs.selector }}&target={{ widget.attrs.id }}"
|
||||||
|
hx-target="#htmx-modal-content"
|
||||||
|
>
|
||||||
|
<i class="mdi mdi-database-search-outline"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% include 'django/forms/widgets/select.html' %}
|
||||||
|
{% endif %}
|
@ -65,41 +65,22 @@ class ClusterForm(TenancyForm, NetBoxModelForm):
|
|||||||
queryset=ClusterGroup.objects.all(),
|
queryset=ClusterGroup.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
site = DynamicModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
query_params={
|
selector=True
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Cluster', ('name', 'type', 'group', 'status', 'description', 'tags')),
|
('Cluster', ('name', 'type', 'group', 'site', 'status', 'description', 'tags')),
|
||||||
('Site', ('region', 'site_group', 'site')),
|
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'type', 'group', 'status', 'tenant', 'region', 'site_group', 'site', 'description', 'comments',
|
'name', 'type', 'group', 'status', 'tenant', 'site', 'description', 'comments', 'tags',
|
||||||
'tags',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -178,20 +159,12 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
cluster_group = DynamicModelChoiceField(
|
|
||||||
queryset=ClusterGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
null_option='None',
|
|
||||||
initial_params={
|
|
||||||
'clusters': '$cluster'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
cluster = DynamicModelChoiceField(
|
cluster = DynamicModelChoiceField(
|
||||||
queryset=Cluster.objects.all(),
|
queryset=Cluster.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
|
selector=True,
|
||||||
query_params={
|
query_params={
|
||||||
'site_id': '$site',
|
'site_id': '$site',
|
||||||
'group_id': '$cluster_group',
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
@ -222,7 +195,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Virtual Machine', ('name', 'role', 'status', 'description', 'tags')),
|
('Virtual Machine', ('name', 'role', 'status', 'description', 'tags')),
|
||||||
('Site/Cluster', ('site', 'cluster_group', 'cluster', 'device')),
|
('Site/Cluster', ('site', 'cluster', 'device')),
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
('Management', ('platform', 'primary_ip4', 'primary_ip6')),
|
('Management', ('platform', 'primary_ip4', 'primary_ip6')),
|
||||||
('Resources', ('vcpus', 'memory', 'disk')),
|
('Resources', ('vcpus', 'memory', 'disk')),
|
||||||
@ -232,9 +205,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'status', 'site', 'cluster_group', 'cluster', 'device', 'role', 'tenant_group', 'tenant',
|
'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4',
|
||||||
'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'tags',
|
'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'tags', 'local_context_data',
|
||||||
'local_context_data',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -280,7 +252,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
|
|
||||||
class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
|
class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
|
||||||
virtual_machine = DynamicModelChoiceField(
|
virtual_machine = DynamicModelChoiceField(
|
||||||
queryset=VirtualMachine.objects.all()
|
queryset=VirtualMachine.objects.all(),
|
||||||
|
selector=True
|
||||||
)
|
)
|
||||||
parent = DynamicModelChoiceField(
|
parent = DynamicModelChoiceField(
|
||||||
queryset=VMInterface.objects.all(),
|
queryset=VMInterface.objects.all(),
|
||||||
|
@ -38,55 +38,16 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm):
|
|||||||
queryset=WirelessLANGroup.objects.all(),
|
queryset=WirelessLANGroup.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
region = DynamicModelChoiceField(
|
|
||||||
queryset=Region.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site_group = DynamicModelChoiceField(
|
|
||||||
queryset=SiteGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
initial_params={
|
|
||||||
'sites': '$site'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
site = DynamicModelChoiceField(
|
|
||||||
queryset=Site.objects.all(),
|
|
||||||
required=False,
|
|
||||||
null_option='None',
|
|
||||||
query_params={
|
|
||||||
'region_id': '$region',
|
|
||||||
'group_id': '$site_group',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
vlan_group = DynamicModelChoiceField(
|
|
||||||
queryset=VLANGroup.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('VLAN group'),
|
|
||||||
null_option='None',
|
|
||||||
query_params={
|
|
||||||
'site': '$site'
|
|
||||||
},
|
|
||||||
initial_params={
|
|
||||||
'vlans': '$vlan'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
vlan = DynamicModelChoiceField(
|
vlan = DynamicModelChoiceField(
|
||||||
queryset=VLAN.objects.all(),
|
queryset=VLAN.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_('VLAN'),
|
selector=True,
|
||||||
query_params={
|
label=_('VLAN')
|
||||||
'site_id': '$site',
|
|
||||||
'group_id': '$vlan_group',
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Wireless LAN', ('ssid', 'group', 'status', 'description', 'tags')),
|
('Wireless LAN', ('ssid', 'group', 'vlan', 'status', 'description', 'tags')),
|
||||||
('VLAN', ('region', 'site_group', 'site', 'vlan_group', 'vlan',)),
|
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
|
('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
|
||||||
)
|
)
|
||||||
@ -94,8 +55,8 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLAN
|
model = WirelessLAN
|
||||||
fields = [
|
fields = [
|
||||||
'ssid', 'group', 'region', 'site_group', 'site', 'status', 'vlan_group', 'vlan', 'tenant_group', 'tenant',
|
'ssid', 'group', 'status', 'vlan', 'tenant_group', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk',
|
||||||
'auth_type', 'auth_cipher', 'auth_psk', 'description', 'comments', 'tags',
|
'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user