mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-29 03:46:25 -06:00
Updated device component connection forms
This commit is contained in:
parent
073051bf49
commit
8cd2d33496
@ -549,7 +549,7 @@ class DeviceForm(BootstrapMixin, CustomFieldForm):
|
||||
if pk and self.instance.device_type.is_child_device and hasattr(self.instance, 'parent_bay'):
|
||||
self.fields['site'].disabled = True
|
||||
self.fields['rack'].disabled = True
|
||||
self.initial['site'] = self.instance.parent_bay.device.rack.site_id
|
||||
self.initial['site'] = self.instance.parent_bay.device.site_id
|
||||
self.initial['rack'] = self.instance.parent_bay.device.rack_id
|
||||
|
||||
|
||||
@ -748,9 +748,13 @@ class ConsolePortCreateForm(BootstrapMixin, forms.Form):
|
||||
|
||||
|
||||
class ConsoleConnectionCSVForm(forms.Form):
|
||||
console_server = FlexibleModelChoiceField(queryset=Device.objects.filter(device_type__is_console_server=True),
|
||||
to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Console server not found'})
|
||||
console_server = FlexibleModelChoiceField(
|
||||
queryset=Device.objects.filter(device_type__is_console_server=True),
|
||||
to_field_name='name',
|
||||
error_messages={
|
||||
'invalid_choice': 'Console server not found',
|
||||
}
|
||||
)
|
||||
cs_port = forms.CharField()
|
||||
device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device not found'})
|
||||
@ -815,22 +819,49 @@ class ConsoleConnectionImportForm(BootstrapMixin, BulkImportForm):
|
||||
|
||||
|
||||
class ConsolePortConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'console_server'}))
|
||||
console_server = forms.ModelChoiceField(queryset=Device.objects.all(), label='Console Server', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_console_server=True',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'cs_port'}))
|
||||
livesearch = forms.CharField(required=False, label='Console Server', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='console_server')
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
widget=forms.HiddenInput(),
|
||||
)
|
||||
rack = forms.ModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'console_server', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
console_server = forms.ModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='Console Server',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}&is_console_server=True',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'cs_port'}
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='Console Server',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='dcim-api:device_list',
|
||||
field_to_update='console_server',
|
||||
)
|
||||
)
|
||||
cs_port = forms.ModelChoiceField(
|
||||
queryset=ConsoleServerPort.objects.all(),
|
||||
label='Port',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/{{console_server}}/console-server-ports/',
|
||||
disabled_indicator='connected_console',
|
||||
)
|
||||
)
|
||||
cs_port = forms.ModelChoiceField(queryset=ConsoleServerPort.objects.all(), label='Port',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{console_server}}/console-server-ports/',
|
||||
disabled_indicator='connected_console'))
|
||||
|
||||
class Meta:
|
||||
model = ConsolePort
|
||||
fields = ['rack', 'console_server', 'livesearch', 'cs_port', 'connection_status']
|
||||
fields = ['site', 'rack', 'console_server', 'livesearch', 'cs_port', 'connection_status']
|
||||
labels = {
|
||||
'cs_port': 'Port',
|
||||
'connection_status': 'Status',
|
||||
@ -843,17 +874,22 @@ class ConsolePortConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
if not self.instance.pk:
|
||||
raise RuntimeError("ConsolePortConnectionForm must be initialized with an existing ConsolePort instance.")
|
||||
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=self.instance.device.rack.site)
|
||||
self.initial['site'] = self.instance.device.site
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=self.instance.device.site)
|
||||
self.fields['cs_port'].required = True
|
||||
self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES
|
||||
|
||||
# Initialize console server choices
|
||||
if self.is_bound and self.data.get('rack'):
|
||||
self.fields['console_server'].queryset = Device.objects.filter(rack=self.data['rack'], device_type__is_console_server=True)
|
||||
self.fields['console_server'].queryset = Device.objects.filter(rack=self.data['rack'],
|
||||
device_type__is_console_server=True)
|
||||
elif self.initial.get('rack'):
|
||||
self.fields['console_server'].queryset = Device.objects.filter(rack=self.initial['rack'], device_type__is_console_server=True)
|
||||
self.fields['console_server'].queryset = Device.objects.filter(rack=self.initial['rack'],
|
||||
device_type__is_console_server=True)
|
||||
else:
|
||||
self.fields['console_server'].choices = []
|
||||
self.fields['console_server'].queryset = Device.objects.filter(site=self.instance.device.site,
|
||||
rack__isnull=True,
|
||||
device_type__is_console_server=True)
|
||||
|
||||
# Initialize CS port choices
|
||||
if self.is_bound:
|
||||
@ -883,10 +919,20 @@ class ConsoleServerPortCreateForm(BootstrapMixin, forms.Form):
|
||||
|
||||
|
||||
class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'device'}))
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
widget=forms.HiddenInput(),
|
||||
)
|
||||
rack = forms.ModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'device', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
|
||||
widget=APISelect(api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}',
|
||||
display_field='display_name', attrs={'filter-for': 'port'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
|
||||
@ -898,7 +944,7 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
|
||||
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
|
||||
|
||||
class Meta:
|
||||
fields = ['rack', 'device', 'livesearch', 'port', 'connection_status']
|
||||
fields = ['site', 'rack', 'device', 'livesearch', 'port', 'connection_status']
|
||||
labels = {
|
||||
'connection_status': 'Status',
|
||||
}
|
||||
@ -907,7 +953,8 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
|
||||
|
||||
super(ConsoleServerPortConnectionForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=consoleserverport.device.rack.site)
|
||||
self.initial['site'] = consoleserverport.device.site
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=consoleserverport.device.site)
|
||||
|
||||
# Initialize device choices
|
||||
if self.is_bound and self.data.get('rack'):
|
||||
@ -915,7 +962,8 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
|
||||
elif self.initial.get('rack', None):
|
||||
self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack'])
|
||||
else:
|
||||
self.fields['device'].choices = []
|
||||
self.fields['device'].queryset = Device.objects.filter(site=consoleserverport.device.site,
|
||||
rack__isnull=True)
|
||||
|
||||
# Initialize port choices
|
||||
if self.is_bound:
|
||||
@ -945,8 +993,13 @@ class PowerPortCreateForm(BootstrapMixin, forms.Form):
|
||||
|
||||
|
||||
class PowerConnectionCSVForm(forms.Form):
|
||||
pdu = FlexibleModelChoiceField(queryset=Device.objects.filter(device_type__is_pdu=True), to_field_name='name',
|
||||
error_messages={'invalid_choice': 'PDU not found.'})
|
||||
pdu = FlexibleModelChoiceField(
|
||||
queryset=Device.objects.filter(device_type__is_pdu=True),
|
||||
to_field_name='name',
|
||||
error_messages={
|
||||
'invalid_choice': 'PDU not found.',
|
||||
}
|
||||
)
|
||||
power_outlet = forms.CharField()
|
||||
device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device not found'})
|
||||
@ -1012,21 +1065,46 @@ class PowerConnectionImportForm(BootstrapMixin, BulkImportForm):
|
||||
|
||||
|
||||
class PowerPortConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'pdu'}))
|
||||
pdu = forms.ModelChoiceField(queryset=Device.objects.all(), label='PDU', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_pdu=True',
|
||||
display_field='display_name', attrs={'filter-for': 'power_outlet'}))
|
||||
livesearch = forms.CharField(required=False, label='PDU', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='pdu')
|
||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.HiddenInput())
|
||||
rack = forms.ModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'pdu', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
pdu = forms.ModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='PDU',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}&is_pdu=True',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'power_outlet'}
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='PDU',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='dcim-api:device_list',
|
||||
field_to_update='pdu'
|
||||
)
|
||||
)
|
||||
power_outlet = forms.ModelChoiceField(
|
||||
queryset=PowerOutlet.objects.all(),
|
||||
label='Outlet',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/{{pdu}}/power-outlets/',
|
||||
disabled_indicator='connected_port'
|
||||
)
|
||||
)
|
||||
power_outlet = forms.ModelChoiceField(queryset=PowerOutlet.objects.all(), label='Outlet',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{pdu}}/power-outlets/',
|
||||
disabled_indicator='connected_port'))
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = ['rack', 'pdu', 'livesearch', 'power_outlet', 'connection_status']
|
||||
fields = ['site', 'rack', 'pdu', 'livesearch', 'power_outlet', 'connection_status']
|
||||
labels = {
|
||||
'power_outlet': 'Outlet',
|
||||
'connection_status': 'Status',
|
||||
@ -1039,17 +1117,22 @@ class PowerPortConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
if not self.instance.pk:
|
||||
raise RuntimeError("PowerPortConnectionForm must be initialized with an existing PowerPort instance.")
|
||||
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=self.instance.device.rack.site)
|
||||
self.initial['site'] = self.instance.device.site
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=self.instance.device.site)
|
||||
self.fields['power_outlet'].required = True
|
||||
self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES
|
||||
|
||||
# Initialize PDU choices
|
||||
if self.is_bound and self.data.get('rack'):
|
||||
self.fields['pdu'].queryset = Device.objects.filter(rack=self.data['rack'], device_type__is_pdu=True)
|
||||
self.fields['pdu'].queryset = Device.objects.filter(rack=self.data['rack'],
|
||||
device_type__is_pdu=True)
|
||||
elif self.initial.get('rack', None):
|
||||
self.fields['pdu'].queryset = Device.objects.filter(rack=self.initial['rack'], device_type__is_pdu=True)
|
||||
self.fields['pdu'].queryset = Device.objects.filter(rack=self.initial['rack'],
|
||||
device_type__is_pdu=True)
|
||||
else:
|
||||
self.fields['pdu'].choices = []
|
||||
self.fields['pdu'].queryset = Device.objects.filter(site=self.instance.device.site,
|
||||
rack__isnull=True,
|
||||
device_type__is_pdu=True)
|
||||
|
||||
# Initialize power outlet choices
|
||||
if self.is_bound:
|
||||
@ -1079,22 +1162,56 @@ class PowerOutletCreateForm(BootstrapMixin, forms.Form):
|
||||
|
||||
|
||||
class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'device'}))
|
||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
|
||||
display_field='display_name', attrs={'filter-for': 'port'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
widget=forms.HiddenInput()
|
||||
)
|
||||
rack = forms.ModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'device', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
device = forms.ModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'port'}
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='Device',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='dcim-api:device_list',
|
||||
field_to_update='device'
|
||||
)
|
||||
)
|
||||
port = forms.ModelChoiceField(
|
||||
queryset=PowerPort.objects.all(),
|
||||
label='Port',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/{{device}}/power-ports/',
|
||||
disabled_indicator='power_outlet'
|
||||
)
|
||||
)
|
||||
connection_status = forms.BooleanField(
|
||||
required=False,
|
||||
initial=CONNECTION_STATUS_CONNECTED,
|
||||
label='Status',
|
||||
widget=forms.Select(
|
||||
choices=CONNECTION_STATUS_CHOICES
|
||||
)
|
||||
)
|
||||
port = forms.ModelChoiceField(queryset=PowerPort.objects.all(), label='Port',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device}}/power-ports/',
|
||||
disabled_indicator='power_outlet'))
|
||||
connection_status = forms.BooleanField(required=False, initial=CONNECTION_STATUS_CONNECTED, label='Status',
|
||||
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
|
||||
|
||||
class Meta:
|
||||
fields = ['rack', 'device', 'livesearch', 'port', 'connection_status']
|
||||
fields = ['site', 'rack', 'device', 'livesearch', 'port', 'connection_status']
|
||||
labels = {
|
||||
'connection_status': 'Status',
|
||||
}
|
||||
@ -1103,7 +1220,8 @@ class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
|
||||
|
||||
super(PowerOutletConnectionForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=poweroutlet.device.rack.site)
|
||||
self.initial['site'] = poweroutlet.device.site
|
||||
self.fields['rack'].queryset = Rack.objects.filter(site=poweroutlet.device.site)
|
||||
|
||||
# Initialize device choices
|
||||
if self.is_bound and self.data.get('rack'):
|
||||
@ -1111,7 +1229,8 @@ class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
|
||||
elif self.initial.get('rack', None):
|
||||
self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack'])
|
||||
else:
|
||||
self.fields['device'].choices = []
|
||||
self.fields['device'].queryset = Device.objects.filter(site=poweroutlet.device.site,
|
||||
rack__isnull=True)
|
||||
|
||||
# Initialize port choices
|
||||
if self.is_bound:
|
||||
@ -1158,22 +1277,55 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
||||
#
|
||||
|
||||
class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
interface_a = forms.ChoiceField(choices=[], widget=SelectWithDisabled, label='Interface')
|
||||
site_b = forms.ModelChoiceField(queryset=Site.objects.all(), label='Site', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'rack_b'}))
|
||||
rack_b = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site_b}}',
|
||||
attrs={'filter-for': 'device_b'}))
|
||||
device_b = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack_b}}',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'interface_b'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device_b')
|
||||
interface_a = forms.ChoiceField(
|
||||
choices=[],
|
||||
widget=SelectWithDisabled,
|
||||
label='Interface'
|
||||
)
|
||||
site_b = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'rack_b'}
|
||||
)
|
||||
)
|
||||
rack_b = forms.ModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{site_b}}',
|
||||
attrs={'filter-for': 'device_b', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
device_b = forms.ModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{site_b}}&rack_id={{rack_b}}',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'interface_b'}
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='Device',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='dcim-api:device_list',
|
||||
field_to_update='device_b'
|
||||
)
|
||||
)
|
||||
interface_b = forms.ModelChoiceField(
|
||||
queryset=Interface.objects.all(),
|
||||
label='Interface',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
|
||||
disabled_indicator='is_connected'
|
||||
)
|
||||
)
|
||||
interface_b = forms.ModelChoiceField(queryset=Interface.objects.all(), label='Interface',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
|
||||
disabled_indicator='is_connected'))
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
@ -1198,11 +1350,15 @@ class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
else:
|
||||
self.fields['rack_b'].choices = []
|
||||
|
||||
# Initialize device_b choices if rack_b is set
|
||||
# Initialize device_b choices if rack_b or site_b is set
|
||||
if self.is_bound and self.data.get('rack_b'):
|
||||
self.fields['device_b'].queryset = Device.objects.filter(rack__pk=self.data['rack_b'])
|
||||
elif self.is_bound and self.data.get('site_b'):
|
||||
self.fields['device_b'].queryset = Device.objects.filter(site__pk=self.data['site_b'], rack__isnull=True)
|
||||
elif self.initial.get('rack_b'):
|
||||
self.fields['device_b'].queryset = Device.objects.filter(rack=self.initial['rack_b'])
|
||||
elif self.initial.get('site_b'):
|
||||
self.fields['device_b'].queryset = Device.objects.filter(site=self.initial['site_b'], rack__isnull=True)
|
||||
else:
|
||||
self.fields['device_b'].choices = []
|
||||
|
||||
@ -1223,13 +1379,21 @@ class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
|
||||
|
||||
|
||||
class InterfaceConnectionCSVForm(forms.Form):
|
||||
device_a = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device A not found.'})
|
||||
device_a = FlexibleModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device A not found.'}
|
||||
)
|
||||
interface_a = forms.CharField()
|
||||
device_b = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device B not found.'})
|
||||
device_b = FlexibleModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
to_field_name='name',
|
||||
error_messages={'invalid_choice': 'Device B not found.'}
|
||||
)
|
||||
interface_b = forms.CharField()
|
||||
status = forms.CharField(validators=[validate_connection_status])
|
||||
status = forms.CharField(
|
||||
validators=[validate_connection_status]
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
|
||||
|
@ -1411,7 +1411,7 @@ def interfaceconnection_add(request, pk):
|
||||
else:
|
||||
form = forms.InterfaceConnectionForm(device, initial={
|
||||
'interface_a': request.GET.get('interface_a', None),
|
||||
'site_b': request.GET.get('site_b', device.rack.site),
|
||||
'site_b': request.GET.get('site_b', device.site),
|
||||
'rack_b': request.GET.get('rack_b', None),
|
||||
'device_b': request.GET.get('device_b', None),
|
||||
'interface_b': request.GET.get('interface_b', None),
|
||||
|
@ -307,10 +307,10 @@ class IPAddressForm(BootstrapMixin, CustomFieldForm):
|
||||
nat_inside = self.instance.nat_inside
|
||||
# If the IP is assigned to an interface, populate site/device fields accordingly
|
||||
if self.instance.nat_inside.interface:
|
||||
self.initial['nat_site'] = self.instance.nat_inside.interface.device.rack.site.pk
|
||||
self.initial['nat_site'] = self.instance.nat_inside.interface.device.site.pk
|
||||
self.initial['nat_device'] = self.instance.nat_inside.interface.device.pk
|
||||
self.fields['nat_device'].queryset = Device.objects.filter(
|
||||
rack__site=nat_inside.interface.device.rack.site)
|
||||
rack__site=nat_inside.interface.device.site)
|
||||
self.fields['nat_inside'].queryset = IPAddress.objects.filter(
|
||||
interface__device=nat_inside.interface.device)
|
||||
else:
|
||||
|
@ -68,38 +68,42 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
// API select widget
|
||||
$('select[filter-for]').change(function () {
|
||||
$('select[filter-for]').change(function() {
|
||||
|
||||
// Resolve child field by ID specified in parent
|
||||
var child_name = $(this).attr('filter-for');
|
||||
var child_field = $('#id_' + child_name);
|
||||
var child_selected = child_field.val();
|
||||
|
||||
// Wipe out any existing options within the child field
|
||||
// Wipe out any existing options within the child field and create a default option
|
||||
child_field.empty();
|
||||
child_field.append($("<option></option>").attr("value", "").text(""));
|
||||
|
||||
if ($(this).val()) {
|
||||
var default_option = $("<option></option>").attr("value", "").text("---------");
|
||||
if (child_field.attr('nullable') == 'true') {
|
||||
default_option.attr("value", "0");
|
||||
}
|
||||
child_field.append(default_option);
|
||||
|
||||
if ($(this).val() || $(this).attr('nullable') == 'true') {
|
||||
var api_url = child_field.attr('api-url');
|
||||
var disabled_indicator = child_field.attr('disabled-indicator');
|
||||
var initial_value = child_field.attr('initial');
|
||||
var display_field = child_field.attr('display-field') || 'name';
|
||||
|
||||
// Gather the values of all other filter fields for this child
|
||||
$("select[filter-for='" + child_name + "']").each(function() {
|
||||
var filter_field = $(this);
|
||||
// Determine the filter fields needed to make an API call
|
||||
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
||||
var match;
|
||||
while (match = filter_regex.exec(api_url)) {
|
||||
var filter_field = $('#id_' + match[1]);
|
||||
if (filter_field.val()) {
|
||||
api_url = api_url.replace('{{' + filter_field.attr('name') + '}}', filter_field.val());
|
||||
api_url = api_url.replace(match[0], filter_field.val());
|
||||
} else {
|
||||
// Not all filters have been selected yet
|
||||
return false;
|
||||
api_url = api_url.replace(match[0], '0');
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// If all URL variables have been replaced, make the API call
|
||||
if (api_url.search('{{') < 0) {
|
||||
console.log(child_name + ": Fetching " + api_url);
|
||||
$.ajax({
|
||||
url: api_url,
|
||||
dataType: 'json',
|
||||
|
@ -7,6 +7,9 @@
|
||||
{% block content %}
|
||||
<form action="." method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
@ -29,6 +32,12 @@
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ consoleport.device.site }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.rack %}
|
||||
{% render_field form.console_server %}
|
||||
</div>
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
{% block content %}
|
||||
<form action="." method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
@ -29,6 +32,12 @@
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ consoleserverport.device.site }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.rack %}
|
||||
{% render_field form.device %}
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a></li>
|
||||
{% if device.rack %}
|
||||
<li><a href="{% url 'dcim:rack_list' %}?site={{ device.rack.site.slug }}">Racks</a></li>
|
||||
<li><a href="{% url 'dcim:rack_list' %}?site={{ device.site.slug }}">Racks</a></li>
|
||||
<li><a href="{% url 'dcim:rack' pk=device.rack.pk %}">{{ device.rack }}</a></li>
|
||||
{% endif %}
|
||||
{% if device.parent_bay %}
|
||||
|
@ -7,88 +7,88 @@
|
||||
{% block content %}
|
||||
<h1>Connect Interfaces</h1>
|
||||
<form action="." method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading"><strong>Errors</strong></div>
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading"><strong>Errors</strong></div>
|
||||
<div class="panel-body">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading text-center">
|
||||
<strong>A Side</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading text-center">
|
||||
<strong>A Side</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device.rack.site }}</p>
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device.site }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Rack</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device.rack }}</p>
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Rack</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device.rack|default:"None" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Device</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device }}</p>
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label required">Device</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ device }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.interface_a %}
|
||||
</div>
|
||||
{% render_field form.interface_a %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2 text-center" style="padding-top: 90px;">
|
||||
<i class="fa fa-exchange fa-4x"></i>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading text-center">
|
||||
<strong>B Side</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#search" aria-controls="search" role="tab" data-toggle="tab">Search</a></li>
|
||||
<li role="presentation"><a href="#select" aria-controls="home" role="tab" data-toggle="tab">Select</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="search">
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
{% render_field form.site_b %}
|
||||
{% render_field form.rack_b %}
|
||||
{% render_field form.device_b %}
|
||||
</div>
|
||||
<div class="col-md-2 text-center" style="padding-top: 90px;">
|
||||
<i class="fa fa-exchange fa-4x"></i>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading text-center">
|
||||
<strong>B Side</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#search" aria-controls="search" role="tab" data-toggle="tab">Search</a></li>
|
||||
<li role="presentation"><a href="#select" aria-controls="home" role="tab" data-toggle="tab">Select</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="search">
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
{% render_field form.site_b %}
|
||||
{% render_field form.rack_b %}
|
||||
{% render_field form.device_b %}
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.interface_b %}
|
||||
</div>
|
||||
{% render_field form.interface_b %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% render_field form.connection_status %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="form-group">
|
||||
<button type="submit" name="_create" class="btn btn-primary">Connect</button>
|
||||
<button type="submit" name="_addanother" class="btn btn-primary">Connect and Add Another</button>
|
||||
<a href="{{ return_url }}" class="btn btn-default">Cancel</a>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% render_field form.connection_status %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="form-group">
|
||||
<button type="submit" name="_create" class="btn btn-primary">Connect</button>
|
||||
<button type="submit" name="_addanother" class="btn btn-primary">Connect and Add Another</button>
|
||||
<a href="{{ return_url }}" class="btn btn-default">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
{% block content %}
|
||||
<form action="." method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
@ -29,6 +32,12 @@
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ poweroutlet.device.site }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.rack %}
|
||||
{% render_field form.device %}
|
||||
</div>
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
{% block content %}
|
||||
<form action="." method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% if form.non_field_errors %}
|
||||
@ -29,6 +32,12 @@
|
||||
{% render_field form.livesearch %}
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">Site</label>
|
||||
<div class="col-md-9">
|
||||
<p class="form-control-static">{{ powerport.device.site }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.rack %}
|
||||
{% render_field form.pdu %}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user