mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-29 11:56: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'):
|
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):
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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:
|
||||||
|
@ -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',
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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 %}
|
||||||
|
@ -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 %}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user