mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 00:28:16 -06:00
Merge e44d0c3ea5
into 78ed85943b
This commit is contained in:
commit
4dc742a9ce
@ -1692,10 +1692,67 @@ class InterfaceBulkDisconnectForm(ConfirmationForm):
|
||||
#
|
||||
|
||||
class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm):
|
||||
interface_a = forms.ChoiceField(
|
||||
choices=[],
|
||||
site_a = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site',
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
attrs={'filter-for': 'rack_a'}
|
||||
)
|
||||
)
|
||||
rack_a = ChainedModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
chains=(
|
||||
('site', 'site_a'),
|
||||
),
|
||||
label='Rack',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{site_a}}',
|
||||
attrs={'filter-for': 'device_a', 'nullable': 'true'}
|
||||
)
|
||||
)
|
||||
device_a = ChainedModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
chains=(
|
||||
('site', 'site_a'),
|
||||
('rack', 'rack_a'),
|
||||
),
|
||||
label='Device',
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{site_a}}&rack_id={{rack_a}}',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'interface_a'}
|
||||
)
|
||||
)
|
||||
livesearch_a = forms.CharField(
|
||||
required=False,
|
||||
label='Device',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='dcim-api:device-list',
|
||||
field_to_update='device_a'
|
||||
)
|
||||
)
|
||||
#interface_a = forms.ChoiceField(
|
||||
# choices=[],
|
||||
# widget=SelectWithDisabled,
|
||||
# label='Interface'
|
||||
#)
|
||||
interface_a = ChainedModelChoiceField(
|
||||
queryset=Interface.objects.connectable().select_related(
|
||||
'circuit_termination', 'connected_as_a', 'connected_as_b'
|
||||
),
|
||||
chains=(
|
||||
('device', 'device_a'),
|
||||
),
|
||||
label='Interface',
|
||||
widget=SelectWithDisabled,
|
||||
label='Interface'
|
||||
#widget=APISelect(
|
||||
# api_url='/api/dcim/interfaces/?device_id={{device_a}}&type=physical',
|
||||
# disabled_indicator='is_connected'
|
||||
#)
|
||||
)
|
||||
site_b = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -1756,20 +1813,34 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['interface_a', 'site_b', 'rack_b', 'device_b', 'interface_b', 'livesearch', 'connection_status']
|
||||
fields = ['site_a','rack_a','device_a','interface_a', 'livesearch_a','site_b', 'rack_b', 'device_b', 'interface_b', 'livesearch', 'connection_status','connection_name']
|
||||
|
||||
def __init__(self, device_a, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super(InterfaceConnectionForm, self).__init__(*args, **kwargs)
|
||||
|
||||
#if self.instance.pk:
|
||||
|
||||
|
||||
#else:
|
||||
|
||||
if self.initial.get('device_a'):
|
||||
|
||||
# Initialize interface A choices
|
||||
device_a_interfaces = Interface.objects.connectable().order_naturally().filter(device=device_a).select_related(
|
||||
device_a_interfaces = Interface.objects.connectable().order_naturally().filter(device=self.initial['device_a']).select_related(
|
||||
'circuit_termination', 'connected_as_a', 'connected_as_b'
|
||||
)
|
||||
|
||||
self.fields['interface_a'].choices = [
|
||||
(iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in device_a_interfaces
|
||||
]
|
||||
|
||||
# Mark connected interfaces as disabled
|
||||
if self.data.get('device_a'):
|
||||
self.fields['interface_a'].choices = [
|
||||
(iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in self.fields['interface_a'].queryset
|
||||
]
|
||||
|
||||
# Mark connected interfaces as disabled
|
||||
if self.data.get('device_b'):
|
||||
self.fields['interface_b'].choices = [
|
||||
@ -1800,10 +1871,14 @@ class InterfaceConnectionCSVForm(forms.ModelForm):
|
||||
choices=CONNECTION_STATUS_CHOICES,
|
||||
help_text='Connection status'
|
||||
)
|
||||
connection_name = forms.CharField(
|
||||
help_text='Name of this connection (e.g. cable-number)',
|
||||
required = False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status']
|
||||
fields = ['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status','connection_name']
|
||||
|
||||
def clean_interface_a(self):
|
||||
|
||||
|
@ -1370,8 +1370,9 @@ class InterfaceConnection(models.Model):
|
||||
interface_b = models.OneToOneField('Interface', related_name='connected_as_b', on_delete=models.CASCADE)
|
||||
connection_status = models.BooleanField(choices=CONNECTION_STATUS_CHOICES, default=CONNECTION_STATUS_CONNECTED,
|
||||
verbose_name='Status')
|
||||
connection_name = models.CharField(max_length = 64,blank = True)
|
||||
|
||||
csv_headers = ['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status']
|
||||
csv_headers = ['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status','connection_name']
|
||||
|
||||
def clean(self):
|
||||
try:
|
||||
@ -1390,6 +1391,7 @@ class InterfaceConnection(models.Model):
|
||||
self.interface_b.device.identifier,
|
||||
self.interface_b.name,
|
||||
self.get_connection_status_display(),
|
||||
self.connection_name,
|
||||
])
|
||||
|
||||
|
||||
|
@ -519,7 +519,8 @@ class InterfaceConnectionTable(BaseTable):
|
||||
device_b = tables.LinkColumn('dcim:device', accessor=Accessor('interface_b.device'),
|
||||
args=[Accessor('interface_b.device.pk')], verbose_name='Device B')
|
||||
interface_b = tables.Column(verbose_name='Interface B')
|
||||
connection_name = tables.Column(verbose_name='Connection Name')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Interface
|
||||
fields = ('device_a', 'interface_a', 'device_b', 'interface_b')
|
||||
fields = ('device_a', 'interface_a', 'device_b', 'interface_b','connection_name')
|
||||
|
@ -182,6 +182,7 @@ urlpatterns = [
|
||||
url(r'^devices/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
|
||||
url(r'^devices/(?P<pk>\d+)/interface-connections/add/$', views.interfaceconnection_add, name='interfaceconnection_add'),
|
||||
url(r'^interface-connections/(?P<pk>\d+)/delete/$', views.interfaceconnection_delete, name='interfaceconnection_delete'),
|
||||
url(r'^interface-connections/(?P<pk>\d+)/edit/$', views.InterfaceConnectionEditView.as_view(), name='interfaceconnection_edit'),
|
||||
url(r'^interfaces/(?P<pk>\d+)/edit/$', views.InterfaceEditView.as_view(), name='interface_edit'),
|
||||
url(r'^interfaces/(?P<pk>\d+)/delete/$', views.InterfaceDeleteView.as_view(), name='interface_delete'),
|
||||
|
||||
|
@ -1682,7 +1682,7 @@ def interfaceconnection_add(request, pk):
|
||||
device = get_object_or_404(Device, pk=pk)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.InterfaceConnectionForm(device, request.POST)
|
||||
form = forms.InterfaceConnectionForm( request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
interfaceconnection = form.save()
|
||||
@ -1709,12 +1709,14 @@ def interfaceconnection_add(request, pk):
|
||||
return redirect('dcim:device', pk=device.pk)
|
||||
|
||||
else:
|
||||
form = forms.InterfaceConnectionForm(device, initial={
|
||||
form = forms.InterfaceConnectionForm(initial={
|
||||
'device_a': pk,
|
||||
'interface_a': request.GET.get('interface_a'),
|
||||
'site_b': request.GET.get('site_b'),
|
||||
'rack_b': request.GET.get('rack_b'),
|
||||
'device_b': request.GET.get('device_b'),
|
||||
'interface_b': request.GET.get('interface_b'),
|
||||
'connection_name': request.GET.get('connection_name'),
|
||||
})
|
||||
|
||||
return render(request, 'dcim/interfaceconnection_edit.html', {
|
||||
@ -1768,6 +1770,21 @@ def interfaceconnection_delete(request, pk):
|
||||
})
|
||||
|
||||
|
||||
class InterfaceConnectionEditView(PermissionRequiredMixin, ObjectEditView):
|
||||
permission_required = 'dcim.edit_interfaceconnection'
|
||||
model = InterfaceConnection
|
||||
#parent_field = 'id'
|
||||
model_form = forms.InterfaceConnectionForm
|
||||
template_name = 'dcim/interfaceconnection_edit.html'
|
||||
|
||||
#template_name = 'dcim/device_edit.html'
|
||||
#default_return_url = 'dcim:device_list'
|
||||
|
||||
#def alter_obj(self, obj, request, url_args, url_kwargs):
|
||||
# if 'device' in url_kwargs:
|
||||
# obj.device = get_object_or_404(InterfaceConnection, pk=url_kwargs['device'])
|
||||
# return obj
|
||||
|
||||
class InterfaceConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
permission_required = 'dcim.change_interface'
|
||||
model_form = forms.InterfaceConnectionCSVForm
|
||||
|
@ -48,6 +48,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<span title="{{ connected_iface.get_form_factor_display }}">{{ connected_iface }}</span>
|
||||
{% if iface.connection.connection_name %}<br /> <small class="text-muted">(via {{ iface.connection.connection_name }})</small>{% endif %}
|
||||
</td>
|
||||
{% endwith %}
|
||||
{% elif iface.circuit_termination %}
|
||||
@ -98,6 +99,9 @@
|
||||
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- <a href="{% url 'dcim:interfaceconnection_edit' pk=iface.connection.pk %}?interface_a={{ iface.pk }}" class="btn btn-info btn-xs" title="Edit Interfaceconnection">
|
||||
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
|
||||
</a> -->
|
||||
<a href="{% url 'dcim:interfaceconnection_delete' pk=iface.connection.pk %}?device={{ device.pk }}" class="btn btn-danger btn-xs" title="Disconnect">
|
||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
@ -82,6 +82,12 @@
|
||||
{% render_field form.connection_status %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- connection name -->
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% render_field form.connection_name %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="form-group">
|
||||
<button type="submit" name="_create" class="btn btn-primary">Connect</button>
|
||||
|
Loading…
Reference in New Issue
Block a user