mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Merge branch 'develop' into v2-develop
This commit is contained in:
commit
5ca87c0f20
@ -10,7 +10,9 @@ Questions? Comments? Please subscribe to [the netbox-discuss mailing list](https
|
|||||||
|
|
||||||
### Build Status
|
### Build Status
|
||||||
|
|
||||||
| | python 2.7 |
|
NetBox is built against both Python 2.7 and 3.5. Python 3.5 is recommended.
|
||||||
|
|
||||||
|
| | status |
|
||||||
|-------------|------------|
|
|-------------|------------|
|
||||||
| **master** | [](https://travis-ci.org/digitalocean/netbox) |
|
| **master** | [](https://travis-ci.org/digitalocean/netbox) |
|
||||||
| **develop** | [](https://travis-ci.org/digitalocean/netbox) |
|
| **develop** | [](https://travis-ci.org/digitalocean/netbox) |
|
||||||
|
@ -10,9 +10,9 @@ from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFi
|
|||||||
from ipam.models import IPAddress
|
from ipam.models import IPAddress
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkImportForm, CommentField,
|
APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||||
CSVDataField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled,
|
BulkImportForm, CommentField, CSVDataField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField,
|
||||||
SmallTextarea, SlugField, FilterTreeNodeMultipleChoiceField,
|
Livesearch, SelectWithDisabled, SmallTextarea, SlugField, FilterTreeNodeMultipleChoiceField,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .formfields import MACAddressFormField
|
from .formfields import MACAddressFormField
|
||||||
@ -271,6 +271,7 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
type = forms.ChoiceField(choices=add_blank_choice(RACK_TYPE_CHOICES), required=False, label='Type')
|
type = forms.ChoiceField(choices=add_blank_choice(RACK_TYPE_CHOICES), required=False, label='Type')
|
||||||
width = forms.ChoiceField(choices=add_blank_choice(RACK_WIDTH_CHOICES), required=False, label='Width')
|
width = forms.ChoiceField(choices=add_blank_choice(RACK_WIDTH_CHOICES), required=False, label='Width')
|
||||||
u_height = forms.IntegerField(required=False, label='Height (U)')
|
u_height = forms.IntegerField(required=False, label='Height (U)')
|
||||||
|
desc_units = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Descending units')
|
||||||
comments = CommentField(widget=SmallTextarea)
|
comments = CommentField(widget=SmallTextarea)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -374,7 +375,13 @@ class DeviceTypeBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
pk = forms.ModelMultipleChoiceField(queryset=DeviceType.objects.all(), widget=forms.MultipleHiddenInput)
|
pk = forms.ModelMultipleChoiceField(queryset=DeviceType.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
||||||
u_height = forms.IntegerField(min_value=1, required=False)
|
u_height = forms.IntegerField(min_value=1, required=False)
|
||||||
|
is_full_depth = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is full depth')
|
||||||
interface_ordering = forms.ChoiceField(choices=add_blank_choice(IFACE_ORDERING_CHOICES), required=False)
|
interface_ordering = forms.ChoiceField(choices=add_blank_choice(IFACE_ORDERING_CHOICES), required=False)
|
||||||
|
is_console_server = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is full depth')
|
||||||
|
is_pdu = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is a PDU')
|
||||||
|
is_network_device = forms.NullBooleanField(
|
||||||
|
required=False, widget=BulkEditNullBooleanSelect, label='Is a network device'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = []
|
nullable_fields = []
|
||||||
@ -483,6 +490,7 @@ class InterfaceTemplateCreateForm(DeviceComponentForm):
|
|||||||
class InterfaceTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
|
class InterfaceTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(queryset=InterfaceTemplate.objects.all(), widget=forms.MultipleHiddenInput)
|
pk = forms.ModelMultipleChoiceField(queryset=InterfaceTemplate.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
form_factor = forms.ChoiceField(choices=add_blank_choice(IFACE_FF_CHOICES), required=False)
|
form_factor = forms.ChoiceField(choices=add_blank_choice(IFACE_FF_CHOICES), required=False)
|
||||||
|
mgmt_only = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Management only')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = []
|
nullable_fields = []
|
||||||
@ -1415,6 +1423,7 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), widget=forms.HiddenInput)
|
device = forms.ModelChoiceField(queryset=Device.objects.all(), widget=forms.HiddenInput)
|
||||||
lag = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Parent LAG')
|
lag = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Parent LAG')
|
||||||
form_factor = forms.ChoiceField(choices=add_blank_choice(IFACE_FF_CHOICES), required=False)
|
form_factor = forms.ChoiceField(choices=add_blank_choice(IFACE_FF_CHOICES), required=False)
|
||||||
|
mgmt_only = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Management only')
|
||||||
description = forms.CharField(max_length=100, required=False)
|
description = forms.CharField(max_length=100, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -12,11 +12,12 @@ from django.http import HttpResponseRedirect
|
|||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
from ipam.models import Prefix, Service, VLAN
|
from ipam.models import Prefix, Service, VLAN
|
||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE, UserAction
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.paginator import EnhancedPaginator
|
from utilities.paginator import EnhancedPaginator
|
||||||
from utilities.views import (
|
from utilities.views import (
|
||||||
@ -892,12 +893,16 @@ def consoleport_connect(request, pk):
|
|||||||
form = forms.ConsolePortConnectionForm(request.POST, instance=consoleport)
|
form = forms.ConsolePortConnectionForm(request.POST, instance=consoleport)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
consoleport = form.save()
|
consoleport = form.save()
|
||||||
messages.success(request, u"Connected {} {} to {} {}.".format(
|
msg = u'Connected <a href="{}">{}</a> {} to <a href="{}">{}</a> {}'.format(
|
||||||
consoleport.device,
|
consoleport.device.get_absolute_url(),
|
||||||
consoleport.name,
|
escape(consoleport.device),
|
||||||
consoleport.cs_port.device,
|
escape(consoleport.name),
|
||||||
consoleport.cs_port.name,
|
consoleport.cs_port.device.get_absolute_url(),
|
||||||
))
|
escape(consoleport.cs_port.device),
|
||||||
|
escape(consoleport.cs_port.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, consoleport, msg)
|
||||||
return redirect('dcim:device', pk=consoleport.device.pk)
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -921,17 +926,28 @@ def consoleport_disconnect(request, pk):
|
|||||||
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
||||||
|
|
||||||
if not consoleport.cs_port:
|
if not consoleport.cs_port:
|
||||||
messages.warning(request, u"Cannot disconnect console port {}: It is not connected to anything."
|
messages.warning(
|
||||||
.format(consoleport))
|
request, u"Cannot disconnect console port {}: It is not connected to anything.".format(consoleport)
|
||||||
|
)
|
||||||
return redirect('dcim:device', pk=consoleport.device.pk)
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ConfirmationForm(request.POST)
|
form = ConfirmationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
cs_port = consoleport.cs_port
|
||||||
consoleport.cs_port = None
|
consoleport.cs_port = None
|
||||||
consoleport.connection_status = None
|
consoleport.connection_status = None
|
||||||
consoleport.save()
|
consoleport.save()
|
||||||
messages.success(request, u"Console port {} has been disconnected.".format(consoleport))
|
msg = u'Disconnected <a href="{}">{}</a> {} from <a href="{}">{}</a> {}'.format(
|
||||||
|
consoleport.device.get_absolute_url(),
|
||||||
|
escape(consoleport.device),
|
||||||
|
escape(consoleport.name),
|
||||||
|
cs_port.device.get_absolute_url(),
|
||||||
|
escape(cs_port.device),
|
||||||
|
escape(cs_port.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, consoleport, msg)
|
||||||
return redirect('dcim:device', pk=consoleport.device.pk)
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -966,6 +982,7 @@ class ConsoleConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
form = forms.ConsoleConnectionImportForm
|
form = forms.ConsoleConnectionImportForm
|
||||||
table = tables.ConsoleConnectionTable
|
table = tables.ConsoleConnectionTable
|
||||||
template_name = 'dcim/console_connections_import.html'
|
template_name = 'dcim/console_connections_import.html'
|
||||||
|
default_return_url = 'dcim:console_connections_list'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -993,12 +1010,16 @@ def consoleserverport_connect(request, pk):
|
|||||||
consoleport.cs_port = consoleserverport
|
consoleport.cs_port = consoleserverport
|
||||||
consoleport.connection_status = form.cleaned_data['connection_status']
|
consoleport.connection_status = form.cleaned_data['connection_status']
|
||||||
consoleport.save()
|
consoleport.save()
|
||||||
messages.success(request, u"Connected {} {} to {} {}.".format(
|
msg = u'Connected <a href="{}">{}</a> {} to <a href="{}">{}</a> {}'.format(
|
||||||
consoleport.device,
|
consoleport.device.get_absolute_url(),
|
||||||
consoleport.name,
|
escape(consoleport.device),
|
||||||
consoleserverport.device,
|
escape(consoleport.name),
|
||||||
consoleserverport.name,
|
consoleserverport.device.get_absolute_url(),
|
||||||
))
|
escape(consoleserverport.device),
|
||||||
|
escape(consoleserverport.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, consoleport, msg)
|
||||||
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1022,8 +1043,9 @@ def consoleserverport_disconnect(request, pk):
|
|||||||
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
||||||
|
|
||||||
if not hasattr(consoleserverport, 'connected_console'):
|
if not hasattr(consoleserverport, 'connected_console'):
|
||||||
messages.warning(request, u"Cannot disconnect console server port {}: Nothing is connected to it."
|
messages.warning(
|
||||||
.format(consoleserverport))
|
request, u"Cannot disconnect console server port {}: Nothing is connected to it.".format(consoleserverport)
|
||||||
|
)
|
||||||
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -1033,7 +1055,16 @@ def consoleserverport_disconnect(request, pk):
|
|||||||
consoleport.cs_port = None
|
consoleport.cs_port = None
|
||||||
consoleport.connection_status = None
|
consoleport.connection_status = None
|
||||||
consoleport.save()
|
consoleport.save()
|
||||||
messages.success(request, u"Console server port {} has been disconnected.".format(consoleserverport))
|
msg = u'Disconnected <a href="{}">{}</a> {} from <a href="{}">{}</a> {}'.format(
|
||||||
|
consoleport.device.get_absolute_url(),
|
||||||
|
escape(consoleport.device),
|
||||||
|
escape(consoleport.name),
|
||||||
|
consoleserverport.device.get_absolute_url(),
|
||||||
|
escape(consoleserverport.device),
|
||||||
|
escape(consoleserverport.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, consoleport, msg)
|
||||||
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1085,12 +1116,16 @@ def powerport_connect(request, pk):
|
|||||||
form = forms.PowerPortConnectionForm(request.POST, instance=powerport)
|
form = forms.PowerPortConnectionForm(request.POST, instance=powerport)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
powerport = form.save()
|
powerport = form.save()
|
||||||
messages.success(request, u"Connected {} {} to {} {}.".format(
|
msg = u'Connected <a href="{}">{}</a> {} to <a href="{}">{}</a> {}'.format(
|
||||||
powerport.device,
|
powerport.device.get_absolute_url(),
|
||||||
powerport.name,
|
escape(powerport.device),
|
||||||
powerport.power_outlet.device,
|
escape(powerport.name),
|
||||||
powerport.power_outlet.name,
|
powerport.power_outlet.device.get_absolute_url(),
|
||||||
))
|
escape(powerport.power_outlet.device),
|
||||||
|
escape(powerport.power_outlet.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, powerport, msg)
|
||||||
return redirect('dcim:device', pk=powerport.device.pk)
|
return redirect('dcim:device', pk=powerport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1114,17 +1149,28 @@ def powerport_disconnect(request, pk):
|
|||||||
powerport = get_object_or_404(PowerPort, pk=pk)
|
powerport = get_object_or_404(PowerPort, pk=pk)
|
||||||
|
|
||||||
if not powerport.power_outlet:
|
if not powerport.power_outlet:
|
||||||
messages.warning(request, u"Cannot disconnect power port {}: It is not connected to an outlet."
|
messages.warning(
|
||||||
.format(powerport))
|
request, u"Cannot disconnect power port {}: It is not connected to an outlet.".format(powerport)
|
||||||
|
)
|
||||||
return redirect('dcim:device', pk=powerport.device.pk)
|
return redirect('dcim:device', pk=powerport.device.pk)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ConfirmationForm(request.POST)
|
form = ConfirmationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
power_outlet = powerport.power_outlet
|
||||||
powerport.power_outlet = None
|
powerport.power_outlet = None
|
||||||
powerport.connection_status = None
|
powerport.connection_status = None
|
||||||
powerport.save()
|
powerport.save()
|
||||||
messages.success(request, u"Power port {} has been disconnected.".format(powerport))
|
msg = u'Disconnected <a href="{}">{}</a> {} from <a href="{}">{}</a> {}'.format(
|
||||||
|
powerport.device.get_absolute_url(),
|
||||||
|
escape(powerport.device),
|
||||||
|
escape(powerport.name),
|
||||||
|
power_outlet.device.get_absolute_url(),
|
||||||
|
escape(power_outlet.device),
|
||||||
|
escape(power_outlet.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, powerport, msg)
|
||||||
return redirect('dcim:device', pk=powerport.device.pk)
|
return redirect('dcim:device', pk=powerport.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1159,6 +1205,7 @@ class PowerConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
form = forms.PowerConnectionImportForm
|
form = forms.PowerConnectionImportForm
|
||||||
table = tables.PowerConnectionTable
|
table = tables.PowerConnectionTable
|
||||||
template_name = 'dcim/power_connections_import.html'
|
template_name = 'dcim/power_connections_import.html'
|
||||||
|
default_return_url = 'dcim:power_connections_list'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1186,12 +1233,16 @@ def poweroutlet_connect(request, pk):
|
|||||||
powerport.power_outlet = poweroutlet
|
powerport.power_outlet = poweroutlet
|
||||||
powerport.connection_status = form.cleaned_data['connection_status']
|
powerport.connection_status = form.cleaned_data['connection_status']
|
||||||
powerport.save()
|
powerport.save()
|
||||||
messages.success(request, u"Connected {} {} to {} {}.".format(
|
msg = u'Connected <a href="{}">{}</a> {} to <a href="{}">{}</a> {}'.format(
|
||||||
powerport.device,
|
powerport.device.get_absolute_url(),
|
||||||
powerport.name,
|
escape(powerport.device),
|
||||||
poweroutlet.device,
|
escape(powerport.name),
|
||||||
poweroutlet.name,
|
poweroutlet.device.get_absolute_url(),
|
||||||
))
|
escape(poweroutlet.device),
|
||||||
|
escape(poweroutlet.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, powerport, msg)
|
||||||
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1215,7 +1266,9 @@ def poweroutlet_disconnect(request, pk):
|
|||||||
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
||||||
|
|
||||||
if not hasattr(poweroutlet, 'connected_port'):
|
if not hasattr(poweroutlet, 'connected_port'):
|
||||||
messages.warning(request, u"Cannot disconnect power outlet {}: Nothing is connected to it.".format(poweroutlet))
|
messages.warning(
|
||||||
|
request, u"Cannot disconnect power outlet {}: Nothing is connected to it.".format(poweroutlet)
|
||||||
|
)
|
||||||
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -1225,7 +1278,16 @@ def poweroutlet_disconnect(request, pk):
|
|||||||
powerport.power_outlet = None
|
powerport.power_outlet = None
|
||||||
powerport.connection_status = None
|
powerport.connection_status = None
|
||||||
powerport.save()
|
powerport.save()
|
||||||
messages.success(request, u"Power outlet {} has been disconnected.".format(poweroutlet))
|
msg = u'Disconnected <a href="{}">{}</a> {} from <a href="{}">{}</a> {}'.format(
|
||||||
|
powerport.device.get_absolute_url(),
|
||||||
|
escape(powerport.device),
|
||||||
|
escape(powerport.name),
|
||||||
|
poweroutlet.device.get_absolute_url(),
|
||||||
|
escape(poweroutlet.device),
|
||||||
|
escape(poweroutlet.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, powerport, msg)
|
||||||
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1491,13 +1553,19 @@ def interfaceconnection_add(request, pk):
|
|||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = forms.InterfaceConnectionForm(device, request.POST)
|
form = forms.InterfaceConnectionForm(device, request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
interfaceconnection = form.save()
|
interfaceconnection = form.save()
|
||||||
messages.success(request, u"Connected {} {} to {} {}.".format(
|
msg = u'Connected <a href="{}">{}</a> {} to <a href="{}">{}</a> {}'.format(
|
||||||
interfaceconnection.interface_a.device,
|
interfaceconnection.interface_a.device.get_absolute_url(),
|
||||||
interfaceconnection.interface_a,
|
escape(interfaceconnection.interface_a.device),
|
||||||
interfaceconnection.interface_b.device,
|
escape(interfaceconnection.interface_a.name),
|
||||||
interfaceconnection.interface_b,
|
interfaceconnection.interface_b.device.get_absolute_url(),
|
||||||
))
|
escape(interfaceconnection.interface_b.device),
|
||||||
|
escape(interfaceconnection.interface_b.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, interfaceconnection, msg)
|
||||||
|
|
||||||
if '_addanother' in request.POST:
|
if '_addanother' in request.POST:
|
||||||
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
|
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
|
||||||
device_b = interfaceconnection.interface_b.device
|
device_b = interfaceconnection.interface_b.device
|
||||||
@ -1535,12 +1603,16 @@ def interfaceconnection_delete(request, pk):
|
|||||||
form = forms.InterfaceConnectionDeletionForm(request.POST)
|
form = forms.InterfaceConnectionDeletionForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
interfaceconnection.delete()
|
interfaceconnection.delete()
|
||||||
messages.success(request, u"Deleted the connection between {} {} and {} {}.".format(
|
msg = u'Disconnected <a href="{}">{}</a> {} from <a href="{}">{}</a> {}'.format(
|
||||||
interfaceconnection.interface_a.device,
|
interfaceconnection.interface_a.device.get_absolute_url(),
|
||||||
interfaceconnection.interface_a,
|
escape(interfaceconnection.interface_a.device),
|
||||||
interfaceconnection.interface_b.device,
|
escape(interfaceconnection.interface_a.name),
|
||||||
interfaceconnection.interface_b,
|
interfaceconnection.interface_b.device.get_absolute_url(),
|
||||||
))
|
escape(interfaceconnection.interface_b.device),
|
||||||
|
escape(interfaceconnection.interface_b.name),
|
||||||
|
)
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_edit(request.user, interfaceconnection, msg)
|
||||||
if form.cleaned_data['device']:
|
if form.cleaned_data['device']:
|
||||||
return redirect('dcim:device', pk=form.cleaned_data['device'].pk)
|
return redirect('dcim:device', pk=form.cleaned_data['device'].pk)
|
||||||
else:
|
else:
|
||||||
@ -1570,6 +1642,7 @@ class InterfaceConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView
|
|||||||
form = forms.InterfaceConnectionImportForm
|
form = forms.InterfaceConnectionImportForm
|
||||||
table = tables.InterfaceConnectionTable
|
table = tables.InterfaceConnectionTable
|
||||||
template_name = 'dcim/interface_connections_import.html'
|
template_name = 'dcim/interface_connections_import.html'
|
||||||
|
default_return_url = 'dcim:interface_connections_list'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -9,7 +9,10 @@ from extras.filters import CustomFieldFilterSet
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||||
|
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import (
|
||||||
|
Aggregate, IPAddress, IPADDRESS_STATUS_CHOICES, Prefix, PREFIX_STATUS_CHOICES, RIR, Role, Service, VLAN,
|
||||||
|
VLAN_STATUS_CHOICES, VLANGroup, VRF,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||||
@ -153,10 +156,13 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Role (slug)',
|
label='Role (slug)',
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=PREFIX_STATUS_CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ['family', 'status']
|
fields = ['family']
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -237,10 +243,13 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
label='Interface (ID)',
|
label='Interface (ID)',
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=IPADDRESS_STATUS_CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = ['family', 'status']
|
fields = ['family']
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -337,10 +346,13 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Role (slug)',
|
label='Role (slug)',
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=VLAN_STATUS_CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLAN
|
model = VLAN
|
||||||
fields = ['name', 'vid', 'status']
|
fields = ['name', 'vid']
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -5,8 +5,8 @@ from dcim.models import Site, Rack, Device, Interface
|
|||||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, BootstrapMixin, BulkImportForm, CSVDataField, ExpandableIPAddressField, FilterChoiceField, Livesearch,
|
APISelect, BootstrapMixin, BulkEditNullBooleanSelect, BulkImportForm, CSVDataField, ExpandableIPAddressField,
|
||||||
ReturnURLForm, SlugField, add_blank_choice,
|
FilterChoiceField, Livesearch, ReturnURLForm, SlugField, add_blank_choice,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
@ -61,6 +61,9 @@ class VRFImportForm(BootstrapMixin, BulkImportForm):
|
|||||||
class VRFBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
class VRFBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(queryset=VRF.objects.all(), widget=forms.MultipleHiddenInput)
|
pk = forms.ModelMultipleChoiceField(queryset=VRF.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
||||||
|
enforce_unique = forms.NullBooleanField(
|
||||||
|
required=False, widget=BulkEditNullBooleanSelect, label='Enforce unique space'
|
||||||
|
)
|
||||||
description = forms.CharField(max_length=100, required=False)
|
description = forms.CharField(max_length=100, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -256,6 +259,7 @@ class PrefixBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
||||||
status = forms.ChoiceField(choices=add_blank_choice(PREFIX_STATUS_CHOICES), required=False)
|
status = forms.ChoiceField(choices=add_blank_choice(PREFIX_STATUS_CHOICES), required=False)
|
||||||
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False)
|
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False)
|
||||||
|
is_pool = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is a pool')
|
||||||
description = forms.CharField(max_length=100, required=False)
|
description = forms.CharField(max_length=100, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -340,10 +344,11 @@ class IPAddressForm(BootstrapMixin, ReturnURLForm, CustomFieldForm):
|
|||||||
query_key='q', query_url='ipam-api:ipaddress-list', field_to_update='nat_inside', obj_label='address'
|
query_key='q', query_url='ipam-api:ipaddress-list', field_to_update='nat_inside', obj_label='address'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
primary_for_device = forms.BooleanField(required=False, label='Make this the primary IP for the device')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = ['address', 'vrf', 'tenant', 'status', 'interface', 'nat_inside', 'description']
|
fields = ['address', 'vrf', 'tenant', 'status', 'description', 'interface', 'primary_for_device', 'nat_inside']
|
||||||
widgets = {
|
widgets = {
|
||||||
'interface': APISelect(api_url='/api/dcim/devices/interfaces/?device_id={{interface_device}}'),
|
'interface': APISelect(api_url='/api/dcim/devices/interfaces/?device_id={{interface_device}}'),
|
||||||
'nat_inside': APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}', display_field='address')
|
'nat_inside': APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}', display_field='address')
|
||||||
@ -384,6 +389,15 @@ class IPAddressForm(BootstrapMixin, ReturnURLForm, CustomFieldForm):
|
|||||||
else:
|
else:
|
||||||
self.fields['interface'].choices = []
|
self.fields['interface'].choices = []
|
||||||
|
|
||||||
|
# Initialize primary_for_device if IP address is already assigned
|
||||||
|
if self.instance.interface is not None:
|
||||||
|
device = self.instance.interface.device
|
||||||
|
if (
|
||||||
|
self.instance.address.version == 4 and device.primary_ip4 == self.instance or
|
||||||
|
self.instance.address.version == 6 and device.primary_ip6 == self.instance
|
||||||
|
):
|
||||||
|
self.initial['primary_for_device'] = True
|
||||||
|
|
||||||
if self.instance.nat_inside:
|
if self.instance.nat_inside:
|
||||||
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
|
||||||
@ -416,6 +430,43 @@ class IPAddressForm(BootstrapMixin, ReturnURLForm, CustomFieldForm):
|
|||||||
else:
|
else:
|
||||||
self.fields['nat_inside'].choices = []
|
self.fields['nat_inside'].choices = []
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super(IPAddressForm, self).clean()
|
||||||
|
|
||||||
|
# Primary IP assignment is only available if an interface has been assigned.
|
||||||
|
if self.cleaned_data.get('primary_for_device') and not self.cleaned_data.get('interface'):
|
||||||
|
self.add_error(
|
||||||
|
'primary_for_device', "Only IP addresses assigned to an interface can be designated as primary IPs."
|
||||||
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
|
ipaddress = super(IPAddressForm, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
# Assign this IPAddress as the primary for the associated Device.
|
||||||
|
if self.cleaned_data['primary_for_device']:
|
||||||
|
device = self.cleaned_data['interface'].device
|
||||||
|
if ipaddress.address.version == 4:
|
||||||
|
device.primary_ip4 = ipaddress
|
||||||
|
else:
|
||||||
|
device.primary_ip6 = ipaddress
|
||||||
|
device.save()
|
||||||
|
|
||||||
|
# Clear assignment as primary for device if set.
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if ipaddress.address.version == 4:
|
||||||
|
device = ipaddress.primary_ip4_for
|
||||||
|
device.primary_ip4 = None
|
||||||
|
else:
|
||||||
|
device = ipaddress.primary_ip6_for
|
||||||
|
device.primary_ip6 = None
|
||||||
|
device.save()
|
||||||
|
except Device.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return ipaddress
|
||||||
|
|
||||||
|
|
||||||
class IPAddressBulkAddForm(BootstrapMixin, CustomFieldForm):
|
class IPAddressBulkAddForm(BootstrapMixin, CustomFieldForm):
|
||||||
address_pattern = ExpandableIPAddressField(label='Address Pattern')
|
address_pattern = ExpandableIPAddressField(label='Address Pattern')
|
||||||
|
@ -221,6 +221,7 @@ def secret_import(request):
|
|||||||
|
|
||||||
return render(request, 'import_success.html', {
|
return render(request, 'import_success.html', {
|
||||||
'table': table,
|
'table': table,
|
||||||
|
'return_url': 'secrets:secret_list',
|
||||||
})
|
})
|
||||||
|
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
@ -231,7 +232,7 @@ def secret_import(request):
|
|||||||
|
|
||||||
return render(request, 'secrets/secret_import.html', {
|
return render(request, 'secrets/secret_import.html', {
|
||||||
'form': form,
|
'form': form,
|
||||||
'return_url': reverse('secrets:secret_list'),
|
'return_url': 'secrets:secret_list',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Circuit Import{% endblock %}
|
{% block title %}Circuit Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Circuit Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -67,6 +54,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>IC-603122,TeliaSonera,Transit,Strickland Propane,2016-02-23,2000,Primary for voice</pre>
|
<pre>IC-603122,TeliaSonera,Transit,Strickland Propane,2016-02-23,2000,Primary for voice</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Provider Import{% endblock %}
|
{% block title %}Provider Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Provider Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -57,6 +44,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>Level 3,level3,3356,08931544,https://mylevel3.net</pre>
|
<pre>Level 3,level3,3356,08931544,https://mylevel3.net</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,22 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Console Connections Import{% endblock %}
|
{% block title %}Console Connections Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Console Connections Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -56,6 +44,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>abc1-cs3,Port 35,abc1-switch7,Console,planned</pre>
|
<pre>abc1-cs3,Port 35,abc1-switch7,Console,planned</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,8 +12,12 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% render_form form %}
|
{% render_form form %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="col-md-12 text-right">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
{% if return_url %}
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
|
@ -12,8 +12,12 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% render_form form %}
|
{% render_form form %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="col-md-12 text-right">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
{% if return_url %}
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<i class="fa fa-fw fa-keyboard-o"></i> {{ cp.name }}
|
<i class="fa fa-fw fa-keyboard-o"></i> {{ cp.name }}
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
{% if cp.cs_port %}
|
{% if cp.cs_port %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'dcim:device' pk=cp.cs_port.device.pk %}">{{ cp.cs_port.device }}</a>
|
<a href="{% url 'dcim:device' pk=cp.cs_port.device.pk %}">{{ cp.cs_port.device }}</a>
|
||||||
@ -32,11 +33,11 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleport_disconnect' pk=cp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleport_disconnect' pk=cp.pk %}" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-remove" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleport_connect' pk=cp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:consoleport_connect' pk=cp.pk %}" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-plus" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleport_edit' pk=cp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:consoleport_edit' pk=cp.pk %}" class="btn btn-info btn-xs">
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<i class="fa fa-fw fa-keyboard-o"></i> {{ csp.name }}
|
<i class="fa fa-fw fa-keyboard-o"></i> {{ csp.name }}
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
{% if csp.connected_console %}
|
{% if csp.connected_console %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'dcim:device' pk=csp.connected_console.device.pk %}">{{ csp.connected_console.device }}</a>
|
<a href="{% url 'dcim:device' pk=csp.connected_console.device.pk %}">{{ csp.connected_console.device }}</a>
|
||||||
@ -32,11 +33,11 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleserverport_disconnect' pk=csp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleserverport_disconnect' pk=csp.pk %}" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-remove" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleserverport_connect' pk=csp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:consoleserverport_connect' pk=csp.pk %}" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-plus" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleserverport_edit' pk=csp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:consoleserverport_edit' pk=csp.pk %}" class="btn btn-info btn-xs">
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
{% if iface.description %}
|
{% if iface.description %}
|
||||||
<i class="fa fa-fw fa-comment-o" title="{{ iface.description }}"></i>
|
<i class="fa fa-fw fa-comment-o" title="{{ iface.description }}"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if iface.is_lag %}
|
|
||||||
<br /><small class="text-muted">{{ iface.member_interfaces.all|join:", "|default:"No members" }}</small>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ iface.mac_address|default:"" }}</td>
|
||||||
{% if iface.is_lag %}
|
{% if iface.is_lag %}
|
||||||
<td colspan="2" class="text-muted">LAG interface</td>
|
<td colspan="2" class="text-muted">
|
||||||
|
LAG interface<br />
|
||||||
|
<small class="text-muted">{{ iface.member_interfaces.all|join:", "|default:"No members" }}</small>
|
||||||
|
</td>
|
||||||
{% elif iface.is_virtual %}
|
{% elif iface.is_virtual %}
|
||||||
<td colspan="2" class="text-muted">Virtual interface</td>
|
<td colspan="2" class="text-muted">Virtual interface</td>
|
||||||
{% elif iface.connection %}
|
{% elif iface.connection %}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<i class="fa fa-fw fa-bolt"></i> {{ po.name }}
|
<i class="fa fa-fw fa-bolt"></i> {{ po.name }}
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
{% if po.connected_port %}
|
{% if po.connected_port %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'dcim:device' pk=po.connected_port.device.pk %}">{{ po.connected_port.device }}</a>
|
<a href="{% url 'dcim:device' pk=po.connected_port.device.pk %}">{{ po.connected_port.device }}</a>
|
||||||
@ -32,11 +33,11 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:poweroutlet_disconnect' pk=po.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:poweroutlet_disconnect' pk=po.pk %}" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-remove" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:poweroutlet_connect' pk=po.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:poweroutlet_connect' pk=po.pk %}" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-plus" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:poweroutlet_edit' pk=po.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:poweroutlet_edit' pk=po.pk %}" class="btn btn-info btn-xs">
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<i class="fa fa-fw fa-bolt"></i> {{ pp.name }}
|
<i class="fa fa-fw fa-bolt"></i> {{ pp.name }}
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
{% if pp.power_outlet %}
|
{% if pp.power_outlet %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'dcim:device' pk=pp.power_outlet.device.pk %}">{{ pp.power_outlet.device }}</a>
|
<a href="{% url 'dcim:device' pk=pp.power_outlet.device.pk %}">{{ pp.power_outlet.device }}</a>
|
||||||
@ -32,11 +33,11 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:powerport_disconnect' pk=pp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:powerport_disconnect' pk=pp.pk %}" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-remove" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:powerport_connect' pk=pp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:powerport_connect' pk=pp.pk %}" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-plus" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:powerport_edit' pk=pp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:powerport_edit' pk=pp.pk %}" class="btn btn-info btn-xs">
|
||||||
|
@ -1,30 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Interface Connections Import{% endblock %}
|
{% block title %}Interface Connections Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Interface Connections Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
{% 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 %}
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -64,6 +44,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>abc1-core1,xe-0/0/6,abc1-switch7,xe-0/0/0,planned</pre>
|
<pre>abc1-core1,xe-0/0/6,abc1-switch7,xe-0/0/0,planned</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,22 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Power Connections Import{% endblock %}
|
{% block title %}Power Connections Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Power Connections Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -56,6 +44,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>abc1-pdu1,AC4,abc1-switch7,PSU0,connected</pre>
|
<pre>abc1-pdu1,AC4,abc1-switch7,PSU0,connected</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Rack Import{% endblock %}
|
{% block title %}Rack Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Rack Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -82,6 +69,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,Compute,4-post cabinet,19,42,False</pre>
|
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,Compute,4-post cabinet,19,42,False</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends '_base.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
|
|
||||||
{% block title %}Import Completed{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Import Completed</h1>
|
<h1>{% block title %}Import Completed{% endblock %}</h1>
|
||||||
{% render_table table %}
|
{% render_table table %}
|
||||||
<a href="{{ request.path }}" class="btn btn-primary">
|
<a href="{{ request.path }}" class="btn btn-primary">
|
||||||
<span class="fa fa-download" aria-hidden="true"></span>
|
<span class="fa fa-download" aria-hidden="true"></span>
|
||||||
Import more
|
Import more
|
||||||
</a>
|
</a>
|
||||||
|
{% if return_url %}
|
||||||
|
<a href="{% url return_url %}" class="btn btn-default">View All</a>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Aggregate Import{% endblock %}
|
{% block title %}Aggregate Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Aggregate Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -52,6 +39,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>172.16.0.0/12,RFC 1918,2016-02-23,Private IPv4 space</pre>
|
<pre>172.16.0.0/12,RFC 1918,2016-02-23,Private IPv4 space</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
{% render_field form.interface_rack %}
|
{% render_field form.interface_rack %}
|
||||||
{% render_field form.interface_device %}
|
{% render_field form.interface_device %}
|
||||||
{% render_field form.interface %}
|
{% render_field form.interface %}
|
||||||
|
{% render_field form.primary_for_device %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}IP Address Import{% endblock %}
|
{% block title %}IP Address Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>IP Address Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -72,6 +59,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>192.0.2.42/24,65000:123,ABC01,Active,switch12,ge-0/0/31,True,Management IP</pre>
|
<pre>192.0.2.42/24,65000:123,ABC01,Active,switch12,ge-0/0/31,True,Management IP</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Prefix Import{% endblock %}
|
{% block title %}Prefix Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Prefix Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -82,6 +69,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>192.168.42.0/24,65000:123,ABC01,HQ,Customers,801,Active,Customer,False,7th floor WiFi</pre>
|
<pre>192.168.42.0/24,65000:123,ABC01,HQ,Customers,801,Active,Customer,False,7th floor WiFi</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}VLAN Import{% endblock %}
|
{% block title %}VLAN Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>VLAN Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -72,6 +59,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>LAS2,Backend Network,1400,Cameras,Internal,Active,Security,Security team only</pre>
|
<pre>LAS2,Backend Network,1400,Cameras,Internal,Active,Security,Security team only</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}VRF Import{% endblock %}
|
{% block title %}VRF Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>VRF Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -57,6 +44,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>Customer_ABC,65000:123456,ABC01,True,Native VRF for customer ABC</pre>
|
<pre>Customer_ABC,65000:123456,ABC01,True,Native VRF for customer ABC</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -21,8 +21,12 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% render_form form %}
|
{% render_form form %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="col-md-12 text-right">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
<a href="{{ return_url }}" class="btn btn-default">Cancel</a>
|
{% if return_url %}
|
||||||
|
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends 'django_tables2/table.html' %}
|
{% extends 'django_tables2/bootstrap-responsive.html' %}
|
||||||
{% load django_tables2 %}
|
{% load django_tables2 %}
|
||||||
|
|
||||||
{# Extends the stock django_tables2 template to provide custom formatting of the pagination controls #}
|
{# Extends the stock django_tables2 template to provide custom formatting of the pagination controls #}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends 'utilities/obj_import.html' %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
{% block title %}Tenant Import{% endblock %}
|
{% block title %}Tenant Import{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block instructions %}
|
||||||
<h1>Tenant Import</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form action="." method="post" class="form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% render_form form %}
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>CSV Format</h4>
|
<h4>CSV Format</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -52,6 +39,4 @@
|
|||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>WIDG01,widg01,Customers,Widgets Inc.</pre>
|
<pre>WIDG01,widg01,Customers,Widgets Inc.</pre>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
34
netbox/templates/utilities/obj_import.html
Normal file
34
netbox/templates/utilities/obj_import.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{% extends '_base.html' %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load form_helpers %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% block title %}{% endblock %}</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{% 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 %}
|
||||||
|
<form action="." method="post" class="form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% render_form form %}
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-12 text-right">
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
{% if return_url %}
|
||||||
|
<a href="{% url return_url %}" class="btn btn-default">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{% block instructions %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -1,4 +1,6 @@
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.utils.html import escape
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
|
||||||
def handle_protectederror(obj, request, e):
|
def handle_protectederror(obj, request, e):
|
||||||
@ -25,11 +27,11 @@ def handle_protectederror(obj, request, e):
|
|||||||
|
|
||||||
# Append dependent objects to error message
|
# Append dependent objects to error message
|
||||||
dependent_objects = []
|
dependent_objects = []
|
||||||
for o in e.protected_objects:
|
for obj in e.protected_objects:
|
||||||
if hasattr(o, 'get_absolute_url'):
|
if hasattr(obj, 'get_absolute_url'):
|
||||||
dependent_objects.append(u'<a href="{}">{}</a>'.format(o.get_absolute_url(), o))
|
dependent_objects.append(u'<a href="{}">{}</a>'.format(obj.get_absolute_url(), escape(obj)))
|
||||||
else:
|
else:
|
||||||
dependent_objects.append(str(o))
|
dependent_objects.append(str(obj))
|
||||||
err_message += u', '.join(dependent_objects)
|
err_message += u', '.join(dependent_objects)
|
||||||
|
|
||||||
messages.error(request, err_message)
|
messages.error(request, mark_safe(err_message))
|
||||||
|
@ -125,6 +125,19 @@ class ColorSelect(forms.Select):
|
|||||||
super(ColorSelect, self).__init__(*args, **kwargs)
|
super(ColorSelect, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class BulkEditNullBooleanSelect(forms.NullBooleanSelect):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(BulkEditNullBooleanSelect, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Override the built-in choice labels
|
||||||
|
self.choices = (
|
||||||
|
('1', '---------'),
|
||||||
|
('2', 'Yes'),
|
||||||
|
('3', 'No'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SelectWithDisabled(forms.Select):
|
class SelectWithDisabled(forms.Select):
|
||||||
"""
|
"""
|
||||||
Modified the stock Select widget to accept choices using a dict() for a label. The dict for each option must include
|
Modified the stock Select widget to accept choices using a dict() for a label. The dict for each option must include
|
||||||
|
@ -17,7 +17,6 @@ from django.utils.http import is_safe_url
|
|||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
from extras.forms import CustomFieldForm
|
|
||||||
from extras.models import CustomField, CustomFieldValue, ExportTemplate, UserAction
|
from extras.models import CustomField, CustomFieldValue, ExportTemplate, UserAction
|
||||||
|
|
||||||
from .error_handlers import handle_protectederror
|
from .error_handlers import handle_protectederror
|
||||||
@ -195,12 +194,8 @@ class ObjectEditView(GetReturnURLMixin, View):
|
|||||||
form = self.form_class(request.POST, request.FILES, instance=obj)
|
form = self.form_class(request.POST, request.FILES, instance=obj)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
obj = form.save(commit=False)
|
obj_created = not form.instance.pk
|
||||||
obj_created = not obj.pk
|
obj = form.save()
|
||||||
obj.save()
|
|
||||||
form.save_m2m()
|
|
||||||
if isinstance(form, CustomFieldForm):
|
|
||||||
form.save_custom_fields()
|
|
||||||
|
|
||||||
msg = u'Created ' if obj_created else u'Modified '
|
msg = u'Created ' if obj_created else u'Modified '
|
||||||
msg += self.model._meta.verbose_name
|
msg += self.model._meta.verbose_name
|
||||||
@ -400,6 +395,7 @@ class BulkImportView(View):
|
|||||||
|
|
||||||
return render(request, "import_success.html", {
|
return render(request, "import_success.html", {
|
||||||
'table': obj_table,
|
'table': obj_table,
|
||||||
|
'return_url': self.default_return_url,
|
||||||
})
|
})
|
||||||
|
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
@ -423,7 +419,7 @@ class BulkEditView(View):
|
|||||||
filter: FilterSet to apply when deleting by QuerySet
|
filter: FilterSet to apply when deleting by QuerySet
|
||||||
form: The form class used to edit objects in bulk
|
form: The form class used to edit objects in bulk
|
||||||
template_name: The name of the template
|
template_name: The name of the template
|
||||||
default_return_url: Name of the URL to which the user is redirected after editing the objects (can be overriden by
|
default_return_url: Name of the URL to which the user is redirected after editing the objects (can be overridden by
|
||||||
POSTing return_url)
|
POSTing return_url)
|
||||||
"""
|
"""
|
||||||
cls = None
|
cls = None
|
||||||
@ -475,7 +471,7 @@ class BulkEditView(View):
|
|||||||
fields_to_update[field] = ''
|
fields_to_update[field] = ''
|
||||||
else:
|
else:
|
||||||
fields_to_update[field] = None
|
fields_to_update[field] = None
|
||||||
elif form.cleaned_data[field]:
|
elif form.cleaned_data[field] not in (None, ''):
|
||||||
fields_to_update[field] = form.cleaned_data[field]
|
fields_to_update[field] = form.cleaned_data[field]
|
||||||
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ django-debug-toolbar>=1.7
|
|||||||
django-filter>=1.0.2
|
django-filter>=1.0.2
|
||||||
django-mptt==0.8.7
|
django-mptt==0.8.7
|
||||||
django-rest-swagger>=2.1.0
|
django-rest-swagger>=2.1.0
|
||||||
django-tables2>=1.4.0
|
django-tables2>=1.6.0
|
||||||
djangorestframework>=3.6.2
|
djangorestframework>=3.6.2
|
||||||
graphviz>=0.6
|
graphviz>=0.6
|
||||||
Markdown>=2.6.7
|
Markdown>=2.6.7
|
||||||
|
Loading…
Reference in New Issue
Block a user