diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 84d4dc39c..003bc408a 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -1120,6 +1120,8 @@ class ConsoleServerPort(models.Model): def clean(self): # Check that the parent device's DeviceType is a console server + if self.device is None: + raise ValidationError("Console server ports must be assigned to devices.") device_type = self.device.device_type if not device_type.is_console_server: raise ValidationError("The {} {} device type not support assignment of console server ports.".format( @@ -1194,6 +1196,8 @@ class PowerOutlet(models.Model): def clean(self): # Check that the parent device's DeviceType is a PDU + if self.device is None: + raise ValidationError("Power outlets must be assigned to devices.") device_type = self.device.device_type if not device_type.is_pdu: raise ValidationError("The {} {} device type not support assignment of power outlets.".format( @@ -1257,11 +1261,12 @@ class Interface(models.Model): def clean(self): # Check that the parent device's DeviceType is a network device - device_type = self.device.device_type - if not device_type.is_network_device: - raise ValidationError("The {} {} device type not support assignment of network interfaces.".format( - device_type.manufacturer, device_type - )) + if self.device is not None: + device_type = self.device.device_type + if not device_type.is_network_device: + raise ValidationError("The {} {} device type not support assignment of network interfaces.".format( + device_type.manufacturer, device_type + )) # An Interface must belong to a Device *or* to a VirtualMachine if self.device and self.virtual_machine: diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d2bac96a6..a5b0a7e3c 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -689,7 +689,7 @@ class IPAddressBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): class IPAddressAssignForm(BootstrapMixin, forms.Form): - vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF') + vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', empty_label='Global') address = forms.CharField(label='IP Address') diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 6e4788840..0ce0afbdf 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -304,6 +304,16 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel): return available_ips + def get_first_available_ip(self): + """ + Return the first available IP within the prefix (or None). + """ + available_ips = self.get_available_ips() + if available_ips: + return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen) + else: + return None + def get_utilization(self): """ Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 791f7a068..73861936b 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -13,7 +13,7 @@ except ImportError: ) -VERSION = '2.2.5' +VERSION = '2.2.6' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/netbox/project-static/css/base.css b/netbox/project-static/css/base.css index dca3cd948..9bf583dd9 100644 --- a/netbox/project-static/css/base.css +++ b/netbox/project-static/css/base.css @@ -35,8 +35,22 @@ footer p { margin: 20px 0; } -/* Collapse the nav menu on displays less than 1200px wide */ +/* Hide the username in the navigation menu on displays less than 1400px wide */ +@media (max-width: 1399px) { + #navbar_user { + display: none; + } +} + +/* Hide the search bar in the navigation menu on displays less than 1200px wide */ @media (max-width: 1199px) { + #navbar_search { + display: none; + } +} + +/* Collapse the nav menu on displays less than 960px wide */ +@media (max-width: 959px) { .navbar-header { float: none; } @@ -72,12 +86,8 @@ footer p { .collapse.in { display:block !important; } -} - -/* Hide the nav search bar on displays less than 1600px wide */ -@media (max-width: 1599px) { - #navbar_search { - display: none; + #navbar_user { + display: inline; } } diff --git a/netbox/templates/circuits/circuittype_list.html b/netbox/templates/circuits/circuittype_list.html index f545b1a1e..ce9cdf385 100644 --- a/netbox/templates/circuits/circuittype_list.html +++ b/netbox/templates/circuits/circuittype_list.html @@ -8,6 +8,10 @@ Add a circuit type + + + Import circuit types + {% endif %}

{% block title %}Circuit Types{% endblock %}

diff --git a/netbox/templates/dcim/devicerole_list.html b/netbox/templates/dcim/devicerole_list.html index 2e8189017..871e62806 100644 --- a/netbox/templates/dcim/devicerole_list.html +++ b/netbox/templates/dcim/devicerole_list.html @@ -8,6 +8,10 @@ Add a device role + + + Import device roles + {% endif %}

{% block title %}Device Roles{% endblock %}

diff --git a/netbox/templates/dcim/platform_list.html b/netbox/templates/dcim/platform_list.html index 124277d0b..dc8d43660 100644 --- a/netbox/templates/dcim/platform_list.html +++ b/netbox/templates/dcim/platform_list.html @@ -8,6 +8,10 @@ Add a platform + + + Import platforms + {% endif %}

{% block title %}Platforms{% endblock %}

diff --git a/netbox/templates/dcim/rackrole_list.html b/netbox/templates/dcim/rackrole_list.html index 1133cf9b2..e18bf7941 100644 --- a/netbox/templates/dcim/rackrole_list.html +++ b/netbox/templates/dcim/rackrole_list.html @@ -8,6 +8,10 @@ Add a rack role + + + Import rack roles + {% endif %}

{% block title %}Rack Roles{% endblock %}

diff --git a/netbox/templates/inc/nav_menu.html b/netbox/templates/inc/nav_menu.html index c1dc9dc67..dd811fb54 100644 --- a/netbox/templates/inc/nav_menu.html +++ b/netbox/templates/inc/nav_menu.html @@ -379,7 +379,9 @@ {% if request.user.is_authenticated %}