Merge branch 'develop' into art-10038

This commit is contained in:
Jeremy Stretch 2022-08-25 13:40:24 -04:00 committed by GitHub
commit 4131bd471b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 119 additions and 109 deletions

View File

@ -54,6 +54,12 @@ NetBox ships with a [git pre-commit hook](https://githooks.com/) script that aut
cd .git/hooks/
ln -s ../../scripts/git-hooks/pre-commit
```
For the pre-commit hooks to work, you will also need to install the pycodestyle package:
```no-highlight
python -m pip install pycodestyle
```
...and setup the yarn packages as shown in the [Web UI Development Guide](web-ui.md)
### 3. Create a Python Virtual Environment
@ -118,6 +124,10 @@ This ensures that your development environment is now complete and operational.
!!! tip "IDE Integration"
Some IDEs, such as the highly-recommended [PyCharm](https://www.jetbrains.com/pycharm/), will integrate with Django's development server and allow you to run it directly within the IDE. This is strongly encouraged as it makes for a much more convenient development environment.
## UI Development
For UI development you will need to review the [Web UI Development Guide](web-ui.md)
## Populating Demo Data
Once you have your development environment up and running, it might be helpful to populate some "dummy" data to make interacting with the UI and APIs more convenient. Check out the [netbox-demo-data](https://github.com/netbox-community/netbox-demo-data) repo on GitHub, which houses a collection of sample data that can be easily imported to any new NetBox deployment. (This sample data is used to populate the public demo instance at <https://demo.netbox.dev>.)

View File

@ -15,17 +15,21 @@
### Bug Fixes
* [#9663](https://github.com/netbox-community/netbox/issues/9663) - Omit available IP annotations when filtering prefix child IPs list
* [#10040](https://github.com/netbox-community/netbox/issues/10040) - Fix exception when ordering prefixes by flat representation
* [#10053](https://github.com/netbox-community/netbox/issues/10053) - Custom fields header should not be displayed when editing circuit terminations with no custom fields
* [#10055](https://github.com/netbox-community/netbox/issues/10055) - Fix extraneous NAT indicator by device primary IP
* [#10057](https://github.com/netbox-community/netbox/issues/10057) - Fix AttributeError exception when global search results include rack reservations
* [#10059](https://github.com/netbox-community/netbox/issues/10059) - Add identifier column to L2VPN table
* [#10070](https://github.com/netbox-community/netbox/issues/10070) - Add unique constraint for L2VPN slug
* [#10087](https://github.com/netbox-community/netbox/issues/10087) - Correct display of far end in console/power/interface connections tables
* [#10089](https://github.com/netbox-community/netbox/issues/10089) - `linkify` template filter should escape object representation
* [#10094](https://github.com/netbox-community/netbox/issues/10094) - Fix 404 when using "create and add another" to add contact assignments
* [#10108](https://github.com/netbox-community/netbox/issues/10108) - Linkify inside NAT IPs for primary device IPs in UI
* [#10109](https://github.com/netbox-community/netbox/issues/10109) - Fix available prefixes calculation for container prefixes in the global table
* [#10111](https://github.com/netbox-community/netbox/issues/10111) - Wrap search QS to catch ValueError on identifier field
* [#10134](https://github.com/netbox-community/netbox/issues/10134) - Custom fields data serializer should return a 400 response for invalid data
* [#10147](https://github.com/netbox-community/netbox/issues/10147) - Permit the creation of 0U device types via REST API
---

View File

@ -310,7 +310,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
max_digits=4,
decimal_places=1,
label='Position (U)',
min_value=decimal.Decimal(0.5),
min_value=0,
default=1.0
)
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)

View File

@ -1,109 +1,8 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from netbox.tables import BaseTable, columns
from dcim.models import ConsolePort, Interface, PowerPort
from .cables import *
from .connections import *
from .devices import *
from .devicetypes import *
from .modules import *
from .power import *
from .racks import *
from .sites import *
#
# Device connections
#
class ConsoleConnectionTable(BaseTable):
console_server = tables.Column(
accessor=Accessor('_path__destination__device'),
orderable=False,
linkify=True,
verbose_name='Console Server'
)
console_server_port = tables.Column(
accessor=Accessor('_path__destination'),
orderable=False,
linkify=True,
verbose_name='Port'
)
device = tables.Column(
linkify=True
)
name = tables.Column(
linkify=True,
verbose_name='Console Port'
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = ConsolePort
fields = ('device', 'name', 'console_server', 'console_server_port', 'reachable')
class PowerConnectionTable(BaseTable):
pdu = tables.Column(
accessor=Accessor('_path__destination__device'),
orderable=False,
linkify=True,
verbose_name='PDU'
)
outlet = tables.Column(
accessor=Accessor('_path__destination'),
orderable=False,
linkify=True,
verbose_name='Outlet'
)
device = tables.Column(
linkify=True
)
name = tables.Column(
linkify=True,
verbose_name='Power Port'
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = PowerPort
fields = ('device', 'name', 'pdu', 'outlet', 'reachable')
class InterfaceConnectionTable(BaseTable):
device_a = tables.Column(
accessor=Accessor('device'),
linkify=True,
verbose_name='Device A'
)
interface_a = tables.Column(
accessor=Accessor('name'),
linkify=True,
verbose_name='Interface A'
)
device_b = tables.Column(
accessor=Accessor('_path__destination__device'),
orderable=False,
linkify=True,
verbose_name='Device B'
)
interface_b = tables.Column(
accessor=Accessor('_path__destination'),
orderable=False,
linkify=True,
verbose_name='Interface B'
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = Interface
fields = ('device_a', 'interface_a', 'device_b', 'interface_b', 'reachable')

View File

@ -0,0 +1,71 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from netbox.tables import BaseTable, columns
from dcim.models import ConsolePort, Interface, PowerPort
from .devices import PathEndpointTable
__all__ = (
'ConsoleConnectionTable',
'InterfaceConnectionTable',
'PowerConnectionTable',
)
#
# Device connections
#
class ConsoleConnectionTable(PathEndpointTable):
device = tables.Column(
linkify=True
)
name = tables.Column(
linkify=True,
verbose_name='Console Port'
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = ConsolePort
fields = ('device', 'name', 'connection', 'reachable')
class PowerConnectionTable(PathEndpointTable):
device = tables.Column(
linkify=True
)
name = tables.Column(
linkify=True,
verbose_name='Power Port'
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = PowerPort
fields = ('device', 'name', 'connection', 'reachable')
class InterfaceConnectionTable(PathEndpointTable):
device = tables.Column(
accessor=Accessor('device'),
linkify=True
)
interface = tables.Column(
accessor=Accessor('name'),
linkify=True
)
reachable = columns.BooleanColumn(
accessor=Accessor('_path__is_active'),
verbose_name='Reachable'
)
class Meta(BaseTable.Meta):
model = Interface
fields = ('device', 'interface', 'connection', 'reachable')

View File

@ -244,6 +244,9 @@ INTERFACE_BUTTONS = """
{% if perms.ipam.add_l2vpntermination %}
<li><a class="dropdown-item" href="{% url 'ipam:l2vpntermination_add' %}?device={{ object.pk }}&interface={{ record.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">L2VPN Termination</a></li>
{% endif %}
{% if perms.ipam.add_fhrpgroupassignment %}
<li><a class="dropdown-item" href="{% url 'ipam:fhrpgroupassignment_add' %}?interface_type={{ record|content_type_id }}&interface_id={{ record.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Assign FHRP Group</a></li>
{% endif %}
</ul>
</span>
{% endif %}

View File

@ -461,16 +461,19 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
'manufacturer': manufacturers[1].pk,
'model': 'Device Type 4',
'slug': 'device-type-4',
'u_height': 0,
},
{
'manufacturer': manufacturers[1].pk,
'model': 'Device Type 5',
'slug': 'device-type-5',
'u_height': 0.5,
},
{
'manufacturer': manufacturers[1].pk,
'model': 'Device Type 6',
'slug': 'device-type-6',
'u_height': 1,
},
]

View File

@ -2893,7 +2893,7 @@ class CableBulkDeleteView(generic.BulkDeleteView):
#
class ConsoleConnectionsListView(generic.ObjectListView):
queryset = ConsolePort.objects.filter(_path__isnull=False).order_by('device')
queryset = ConsolePort.objects.filter(_path__is_complete=True)
filterset = filtersets.ConsoleConnectionFilterSet
filterset_form = forms.ConsoleConnectionFilterForm
table = tables.ConsoleConnectionTable
@ -2907,7 +2907,7 @@ class ConsoleConnectionsListView(generic.ObjectListView):
class PowerConnectionsListView(generic.ObjectListView):
queryset = PowerPort.objects.filter(_path__isnull=False).order_by('device')
queryset = PowerPort.objects.filter(_path__is_complete=True)
filterset = filtersets.PowerConnectionFilterSet
filterset_form = forms.PowerConnectionFilterForm
table = tables.PowerConnectionTable
@ -2921,7 +2921,7 @@ class PowerConnectionsListView(generic.ObjectListView):
class InterfaceConnectionsListView(generic.ObjectListView):
queryset = Interface.objects.filter(_path__isnull=False).order_by('device')
queryset = Interface.objects.filter(_path__is_complete=True)
filterset = filtersets.InterfaceConnectionFilterSet
filterset_form = forms.InterfaceConnectionFilterForm
table = tables.InterfaceConnectionTable

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.7 on 2022-08-22 15:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ipam', '0059_l2vpn'),
]
operations = [
migrations.AlterField(
model_name='l2vpn',
name='slug',
field=models.SlugField(max_length=100, unique=True),
),
]

View File

@ -21,7 +21,10 @@ class L2VPN(NetBoxModel):
max_length=100,
unique=True
)
slug = models.SlugField()
slug = models.SlugField(
max_length=100,
unique=True
)
type = models.CharField(
max_length=50,
choices=L2VPNTypeChoices

View File

@ -526,8 +526,7 @@ class PrefixIPAddressesView(generic.ObjectChildrenView):
return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant', 'tenant__group')
def prep_table_data(self, request, queryset, parent):
show_available = bool(request.GET.get('show_available', 'true') == 'true')
if show_available:
if not request.GET.get('q'):
return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
return queryset