Updated device component connection forms

This commit is contained in:
Jeremy Stretch 2017-02-17 13:43:11 -05:00
parent 073051bf49
commit 8cd2d33496
10 changed files with 373 additions and 169 deletions

View File

@ -549,7 +549,7 @@ class DeviceForm(BootstrapMixin, CustomFieldForm):
if pk and self.instance.device_type.is_child_device and hasattr(self.instance, 'parent_bay'): if pk and self.instance.device_type.is_child_device and hasattr(self.instance, 'parent_bay'):
self.fields['site'].disabled = True self.fields['site'].disabled = True
self.fields['rack'].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 self.initial['rack'] = self.instance.parent_bay.device.rack_id
@ -748,9 +748,13 @@ class ConsolePortCreateForm(BootstrapMixin, forms.Form):
class ConsoleConnectionCSVForm(forms.Form): class ConsoleConnectionCSVForm(forms.Form):
console_server = FlexibleModelChoiceField(queryset=Device.objects.filter(device_type__is_console_server=True), console_server = FlexibleModelChoiceField(
to_field_name='name', queryset=Device.objects.filter(device_type__is_console_server=True),
error_messages={'invalid_choice': 'Console server not found'}) to_field_name='name',
error_messages={
'invalid_choice': 'Console server not found',
}
)
cs_port = forms.CharField() cs_port = forms.CharField()
device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name', device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
error_messages={'invalid_choice': 'Device not found'}) error_messages={'invalid_choice': 'Device not found'})
@ -815,22 +819,49 @@ class ConsoleConnectionImportForm(BootstrapMixin, BulkImportForm):
class ConsolePortConnectionForm(BootstrapMixin, forms.ModelForm): class ConsolePortConnectionForm(BootstrapMixin, forms.ModelForm):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False, site = forms.ModelChoiceField(
widget=forms.Select(attrs={'filter-for': 'console_server'})) queryset=Site.objects.all(),
console_server = forms.ModelChoiceField(queryset=Device.objects.all(), label='Console Server', required=False, widget=forms.HiddenInput(),
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_console_server=True', )
display_field='display_name', rack = forms.ModelChoiceField(
attrs={'filter-for': 'cs_port'})) queryset=Rack.objects.all(),
livesearch = forms.CharField(required=False, label='Console Server', widget=Livesearch( label='Rack',
query_key='q', query_url='dcim-api:device_list', field_to_update='console_server') 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: class Meta:
model = ConsolePort model = ConsolePort
fields = ['rack', 'console_server', 'livesearch', 'cs_port', 'connection_status'] fields = ['site', 'rack', 'console_server', 'livesearch', 'cs_port', 'connection_status']
labels = { labels = {
'cs_port': 'Port', 'cs_port': 'Port',
'connection_status': 'Status', 'connection_status': 'Status',
@ -843,17 +874,22 @@ class ConsolePortConnectionForm(BootstrapMixin, forms.ModelForm):
if not self.instance.pk: if not self.instance.pk:
raise RuntimeError("ConsolePortConnectionForm must be initialized with an existing ConsolePort instance.") 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['cs_port'].required = True
self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES
# Initialize console server choices # Initialize console server choices
if self.is_bound and self.data.get('rack'): 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'): 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: 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 # Initialize CS port choices
if self.is_bound: if self.is_bound:
@ -883,10 +919,20 @@ class ConsoleServerPortCreateForm(BootstrapMixin, forms.Form):
class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form): class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False, site = forms.ModelChoiceField(
widget=forms.Select(attrs={'filter-for': 'device'})) 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, 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'})) display_field='display_name', attrs={'filter-for': 'port'}))
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch( livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='device') 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)) widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
class Meta: class Meta:
fields = ['rack', 'device', 'livesearch', 'port', 'connection_status'] fields = ['site', 'rack', 'device', 'livesearch', 'port', 'connection_status']
labels = { labels = {
'connection_status': 'Status', 'connection_status': 'Status',
} }
@ -907,7 +953,8 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
super(ConsoleServerPortConnectionForm, self).__init__(*args, **kwargs) 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 # Initialize device choices
if self.is_bound and self.data.get('rack'): if self.is_bound and self.data.get('rack'):
@ -915,7 +962,8 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, forms.Form):
elif self.initial.get('rack', None): elif self.initial.get('rack', None):
self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack']) self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack'])
else: else:
self.fields['device'].choices = [] self.fields['device'].queryset = Device.objects.filter(site=consoleserverport.device.site,
rack__isnull=True)
# Initialize port choices # Initialize port choices
if self.is_bound: if self.is_bound:
@ -945,8 +993,13 @@ class PowerPortCreateForm(BootstrapMixin, forms.Form):
class PowerConnectionCSVForm(forms.Form): class PowerConnectionCSVForm(forms.Form):
pdu = FlexibleModelChoiceField(queryset=Device.objects.filter(device_type__is_pdu=True), to_field_name='name', pdu = FlexibleModelChoiceField(
error_messages={'invalid_choice': 'PDU not found.'}) queryset=Device.objects.filter(device_type__is_pdu=True),
to_field_name='name',
error_messages={
'invalid_choice': 'PDU not found.',
}
)
power_outlet = forms.CharField() power_outlet = forms.CharField()
device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name', device = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name',
error_messages={'invalid_choice': 'Device not found'}) error_messages={'invalid_choice': 'Device not found'})
@ -1012,21 +1065,46 @@ class PowerConnectionImportForm(BootstrapMixin, BulkImportForm):
class PowerPortConnectionForm(BootstrapMixin, forms.ModelForm): class PowerPortConnectionForm(BootstrapMixin, forms.ModelForm):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False, site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.HiddenInput())
widget=forms.Select(attrs={'filter-for': 'pdu'})) rack = forms.ModelChoiceField(
pdu = forms.ModelChoiceField(queryset=Device.objects.all(), label='PDU', required=False, queryset=Rack.objects.all(),
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_pdu=True', label='Rack',
display_field='display_name', attrs={'filter-for': 'power_outlet'})) required=False,
livesearch = forms.CharField(required=False, label='PDU', widget=Livesearch( widget=forms.Select(
query_key='q', query_url='dcim-api:device_list', field_to_update='pdu') 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: class Meta:
model = PowerPort model = PowerPort
fields = ['rack', 'pdu', 'livesearch', 'power_outlet', 'connection_status'] fields = ['site', 'rack', 'pdu', 'livesearch', 'power_outlet', 'connection_status']
labels = { labels = {
'power_outlet': 'Outlet', 'power_outlet': 'Outlet',
'connection_status': 'Status', 'connection_status': 'Status',
@ -1039,17 +1117,22 @@ class PowerPortConnectionForm(BootstrapMixin, forms.ModelForm):
if not self.instance.pk: if not self.instance.pk:
raise RuntimeError("PowerPortConnectionForm must be initialized with an existing PowerPort instance.") 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['power_outlet'].required = True
self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES self.fields['connection_status'].choices = CONNECTION_STATUS_CHOICES
# Initialize PDU choices # Initialize PDU choices
if self.is_bound and self.data.get('rack'): 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): 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: 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 # Initialize power outlet choices
if self.is_bound: if self.is_bound:
@ -1079,22 +1162,56 @@ class PowerOutletCreateForm(BootstrapMixin, forms.Form):
class PowerOutletConnectionForm(BootstrapMixin, forms.Form): class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False, site = forms.ModelChoiceField(
widget=forms.Select(attrs={'filter-for': 'device'})) queryset=Site.objects.all(),
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False, widget=forms.HiddenInput()
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}', )
display_field='display_name', attrs={'filter-for': 'port'})) rack = forms.ModelChoiceField(
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch( queryset=Rack.objects.all(),
query_key='q', query_url='dcim-api:device_list', field_to_update='device') 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: class Meta:
fields = ['rack', 'device', 'livesearch', 'port', 'connection_status'] fields = ['site', 'rack', 'device', 'livesearch', 'port', 'connection_status']
labels = { labels = {
'connection_status': 'Status', 'connection_status': 'Status',
} }
@ -1103,7 +1220,8 @@ class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
super(PowerOutletConnectionForm, self).__init__(*args, **kwargs) 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 # Initialize device choices
if self.is_bound and self.data.get('rack'): if self.is_bound and self.data.get('rack'):
@ -1111,7 +1229,8 @@ class PowerOutletConnectionForm(BootstrapMixin, forms.Form):
elif self.initial.get('rack', None): elif self.initial.get('rack', None):
self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack']) self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack'])
else: else:
self.fields['device'].choices = [] self.fields['device'].queryset = Device.objects.filter(site=poweroutlet.device.site,
rack__isnull=True)
# Initialize port choices # Initialize port choices
if self.is_bound: if self.is_bound:
@ -1158,22 +1277,55 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
# #
class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm): class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
interface_a = forms.ChoiceField(choices=[], widget=SelectWithDisabled, label='Interface') interface_a = forms.ChoiceField(
site_b = forms.ModelChoiceField(queryset=Site.objects.all(), label='Site', required=False, choices=[],
widget=forms.Select(attrs={'filter-for': 'rack_b'})) widget=SelectWithDisabled,
rack_b = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False, label='Interface'
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site_b}}', )
attrs={'filter-for': 'device_b'})) site_b = forms.ModelChoiceField(
device_b = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False, queryset=Site.objects.all(),
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack_b}}', label='Site',
display_field='display_name', required=False,
attrs={'filter-for': 'interface_b'})) widget=forms.Select(
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch( attrs={'filter-for': 'rack_b'}
query_key='q', query_url='dcim-api:device_list', field_to_update='device_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: class Meta:
model = InterfaceConnection model = InterfaceConnection
@ -1198,11 +1350,15 @@ class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
else: else:
self.fields['rack_b'].choices = [] 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'): if self.is_bound and self.data.get('rack_b'):
self.fields['device_b'].queryset = Device.objects.filter(rack__pk=self.data['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'): elif self.initial.get('rack_b'):
self.fields['device_b'].queryset = Device.objects.filter(rack=self.initial['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: else:
self.fields['device_b'].choices = [] self.fields['device_b'].choices = []
@ -1223,13 +1379,21 @@ class InterfaceConnectionForm(BootstrapMixin, forms.ModelForm):
class InterfaceConnectionCSVForm(forms.Form): class InterfaceConnectionCSVForm(forms.Form):
device_a = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name', device_a = FlexibleModelChoiceField(
error_messages={'invalid_choice': 'Device A not found.'}) queryset=Device.objects.all(),
to_field_name='name',
error_messages={'invalid_choice': 'Device A not found.'}
)
interface_a = forms.CharField() interface_a = forms.CharField()
device_b = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name', device_b = FlexibleModelChoiceField(
error_messages={'invalid_choice': 'Device B not found.'}) queryset=Device.objects.all(),
to_field_name='name',
error_messages={'invalid_choice': 'Device B not found.'}
)
interface_b = forms.CharField() interface_b = forms.CharField()
status = forms.CharField(validators=[validate_connection_status]) status = forms.CharField(
validators=[validate_connection_status]
)
def clean(self): def clean(self):

View File

@ -1411,7 +1411,7 @@ def interfaceconnection_add(request, pk):
else: else:
form = forms.InterfaceConnectionForm(device, initial={ form = forms.InterfaceConnectionForm(device, initial={
'interface_a': request.GET.get('interface_a', None), '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), 'rack_b': request.GET.get('rack_b', None),
'device_b': request.GET.get('device_b', None), 'device_b': request.GET.get('device_b', None),
'interface_b': request.GET.get('interface_b', None), 'interface_b': request.GET.get('interface_b', None),

View File

@ -307,10 +307,10 @@ class IPAddressForm(BootstrapMixin, CustomFieldForm):
nat_inside = self.instance.nat_inside nat_inside = self.instance.nat_inside
# If the IP is assigned to an interface, populate site/device fields accordingly # If the IP is assigned to an interface, populate site/device fields accordingly
if self.instance.nat_inside.interface: 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.initial['nat_device'] = self.instance.nat_inside.interface.device.pk
self.fields['nat_device'].queryset = Device.objects.filter( 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( self.fields['nat_inside'].queryset = IPAddress.objects.filter(
interface__device=nat_inside.interface.device) interface__device=nat_inside.interface.device)
else: else:

View File

@ -68,38 +68,42 @@ $(document).ready(function() {
}); });
// API select widget // API select widget
$('select[filter-for]').change(function () { $('select[filter-for]').change(function() {
// Resolve child field by ID specified in parent // Resolve child field by ID specified in parent
var child_name = $(this).attr('filter-for'); var child_name = $(this).attr('filter-for');
var child_field = $('#id_' + child_name); var child_field = $('#id_' + child_name);
var child_selected = child_field.val(); 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.empty();
child_field.append($("<option></option>").attr("value", "").text("")); var default_option = $("<option></option>").attr("value", "").text("---------");
if (child_field.attr('nullable') == 'true') {
if ($(this).val()) { 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 api_url = child_field.attr('api-url');
var disabled_indicator = child_field.attr('disabled-indicator'); var disabled_indicator = child_field.attr('disabled-indicator');
var initial_value = child_field.attr('initial'); var initial_value = child_field.attr('initial');
var display_field = child_field.attr('display-field') || 'name'; var display_field = child_field.attr('display-field') || 'name';
// Gather the values of all other filter fields for this child // Determine the filter fields needed to make an API call
$("select[filter-for='" + child_name + "']").each(function() { var filter_regex = /\{\{([a-z_]+)\}\}/g;
var filter_field = $(this); var match;
while (match = filter_regex.exec(api_url)) {
var filter_field = $('#id_' + match[1]);
if (filter_field.val()) { 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 { } else {
// Not all filters have been selected yet api_url = api_url.replace(match[0], '0');
return false;
} }
}
});
// If all URL variables have been replaced, make the API call // If all URL variables have been replaced, make the API call
if (api_url.search('{{') < 0) { if (api_url.search('{{') < 0) {
console.log(child_name + ": Fetching " + api_url);
$.ajax({ $.ajax({
url: api_url, url: api_url,
dataType: 'json', dataType: 'json',

View File

@ -7,6 +7,9 @@
{% block content %} {% block content %}
<form action="." method="post" class="form form-horizontal"> <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="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %} {% if form.non_field_errors %}
@ -29,6 +32,12 @@
{% render_field form.livesearch %} {% render_field form.livesearch %}
</div> </div>
<div class="tab-pane" id="select"> <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.rack %}
{% render_field form.console_server %} {% render_field form.console_server %}
</div> </div>

View File

@ -6,7 +6,10 @@
{% block content %} {% block content %}
<form action="." method="post" class="form form-horizontal"> <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="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %} {% if form.non_field_errors %}
@ -29,6 +32,12 @@
{% render_field form.livesearch %} {% render_field form.livesearch %}
</div> </div>
<div class="tab-pane" id="select"> <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.rack %}
{% render_field form.device %} {% render_field form.device %}
</div> </div>

View File

@ -3,7 +3,7 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a></li> <li><a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a></li>
{% if device.rack %} {% 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> <li><a href="{% url 'dcim:rack' pk=device.rack.pk %}">{{ device.rack }}</a></li>
{% endif %} {% endif %}
{% if device.parent_bay %} {% if device.parent_bay %}

View File

@ -7,88 +7,88 @@
{% block content %} {% block content %}
<h1>Connect Interfaces</h1> <h1>Connect Interfaces</h1>
<form action="." method="post" class="form form-horizontal"> <form action="." method="post" class="form form-horizontal">
{% csrf_token %} {% csrf_token %}
<div class="row"> <div class="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %} {% if form.non_field_errors %}
<div class="panel panel-danger"> <div class="panel panel-danger">
<div class="panel-heading"><strong>Errors</strong></div> <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"> <div class="panel-body">
{{ form.non_field_errors }} <div class="form-group">
</div> <label class="col-md-3 control-label required">Site</label>
</div> <div class="col-md-9">
{% endif %} <p class="form-control-static">{{ device.site }}</p>
</div> </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> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-md-3 control-label required">Rack</label>
<label class="col-md-3 control-label required">Rack</label> <div class="col-md-9">
<div class="col-md-9"> <p class="form-control-static">{{ device.rack|default:"None" }}</p>
<p class="form-control-static">{{ device.rack }}</p> </div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <label class="col-md-3 control-label required">Device</label>
<label class="col-md-3 control-label required">Device</label> <div class="col-md-9">
<div class="col-md-9"> <p class="form-control-static">{{ device }}</p>
<p class="form-control-static">{{ device }}</p> </div>
</div> </div>
{% render_field form.interface_a %}
</div> </div>
{% render_field form.interface_a %}
</div> </div>
</div> </div>
</div> <div class="col-md-2 text-center" style="padding-top: 90px;">
<div class="col-md-2 text-center" style="padding-top: 90px;"> <i class="fa fa-exchange fa-4x"></i>
<i class="fa fa-exchange fa-4x"></i> </div>
</div> <div class="col-md-5">
<div class="col-md-5"> <div class="panel panel-default">
<div class="panel panel-default"> <div class="panel-heading text-center">
<div class="panel-heading text-center"> <strong>B Side</strong>
<strong>B Side</strong> </div>
</div> <div class="panel-body">
<div class="panel-body"> <ul class="nav nav-tabs" role="tablist">
<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" 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>
<li role="presentation"><a href="#select" aria-controls="home" role="tab" data-toggle="tab">Select</a></li> </ul>
</ul> <div class="tab-content">
<div class="tab-content"> <div class="tab-pane active" id="search">
<div class="tab-pane active" id="search"> {% render_field form.livesearch %}
{% render_field form.livesearch %} </div>
</div> <div class="tab-pane" id="select">
<div class="tab-pane" id="select"> {% render_field form.site_b %}
{% render_field form.site_b %} {% render_field form.rack_b %}
{% render_field form.rack_b %} {% render_field form.device_b %}
{% render_field form.device_b %} </div>
</div> </div>
{% render_field form.interface_b %}
</div> </div>
{% render_field form.interface_b %}
</div> </div>
</div> </div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
{% render_field form.connection_status %}
</div> </div>
</div> <div class="row">
<div class="text-center"> <div class="col-md-4 col-md-offset-4">
<div class="form-group"> {% render_field form.connection_status %}
<button type="submit" name="_create" class="btn btn-primary">Connect</button> </div>
<button type="submit" name="_addanother" class="btn btn-primary">Connect and Add Another</button> </div>
<a href="{{ return_url }}" class="btn btn-default">Cancel</a> <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>
</div>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -6,7 +6,10 @@
{% block content %} {% block content %}
<form action="." method="post" class="form form-horizontal"> <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="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %} {% if form.non_field_errors %}
@ -29,6 +32,12 @@
{% render_field form.livesearch %} {% render_field form.livesearch %}
</div> </div>
<div class="tab-pane" id="select"> <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.rack %}
{% render_field form.device %} {% render_field form.device %}
</div> </div>

View File

@ -6,7 +6,10 @@
{% block content %} {% block content %}
<form action="." method="post" class="form form-horizontal"> <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="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %} {% if form.non_field_errors %}
@ -29,6 +32,12 @@
{% render_field form.livesearch %} {% render_field form.livesearch %}
</div> </div>
<div class="tab-pane" id="select"> <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.rack %}
{% render_field form.pdu %} {% render_field form.pdu %}
</div> </div>