mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Add status field to WirelessLink
This commit is contained in:
parent
ec0560a2c5
commit
95ed07a95e
@ -757,7 +757,7 @@ class CableSerializer(PrimaryModelSerializer):
|
|||||||
)
|
)
|
||||||
termination_a = serializers.SerializerMethodField(read_only=True)
|
termination_a = serializers.SerializerMethodField(read_only=True)
|
||||||
termination_b = serializers.SerializerMethodField(read_only=True)
|
termination_b = serializers.SerializerMethodField(read_only=True)
|
||||||
status = ChoiceField(choices=CableStatusChoices, required=False)
|
status = ChoiceField(choices=LinkStatusChoices, required=False)
|
||||||
length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False)
|
length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1030,7 +1030,7 @@ class PortTypeChoices(ChoiceSet):
|
|||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cables
|
# Cables/links
|
||||||
#
|
#
|
||||||
|
|
||||||
class CableTypeChoices(ChoiceSet):
|
class CableTypeChoices(ChoiceSet):
|
||||||
@ -1094,7 +1094,7 @@ class CableTypeChoices(ChoiceSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CableStatusChoices(ChoiceSet):
|
class LinkStatusChoices(ChoiceSet):
|
||||||
|
|
||||||
STATUS_CONNECTED = 'connected'
|
STATUS_CONNECTED = 'connected'
|
||||||
STATUS_PLANNED = 'planned'
|
STATUS_PLANNED = 'planned'
|
||||||
|
@ -1205,7 +1205,7 @@ class CableFilterSet(PrimaryModelFilterSet):
|
|||||||
choices=CableTypeChoices
|
choices=CableTypeChoices
|
||||||
)
|
)
|
||||||
status = django_filters.MultipleChoiceFilter(
|
status = django_filters.MultipleChoiceFilter(
|
||||||
choices=CableStatusChoices
|
choices=LinkStatusChoices
|
||||||
)
|
)
|
||||||
color = django_filters.MultipleChoiceFilter(
|
color = django_filters.MultipleChoiceFilter(
|
||||||
choices=ColorChoices
|
choices=ColorChoices
|
||||||
|
@ -453,7 +453,7 @@ class CableBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkE
|
|||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(CableStatusChoices),
|
choices=add_blank_choice(LinkStatusChoices),
|
||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect(),
|
widget=StaticSelect(),
|
||||||
initial=''
|
initial=''
|
||||||
|
@ -807,7 +807,7 @@ class CableCSVForm(CustomFieldModelCSVForm):
|
|||||||
|
|
||||||
# Cable attributes
|
# Cable attributes
|
||||||
status = CSVChoiceField(
|
status = CSVChoiceField(
|
||||||
choices=CableStatusChoices,
|
choices=LinkStatusChoices,
|
||||||
required=False,
|
required=False,
|
||||||
help_text='Connection status'
|
help_text='Connection status'
|
||||||
)
|
)
|
||||||
|
@ -732,7 +732,7 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
|||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=add_blank_choice(CableStatusChoices),
|
choices=add_blank_choice(LinkStatusChoices),
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
color = ColorField(
|
color = ColorField(
|
||||||
|
@ -64,8 +64,8 @@ class Cable(PrimaryModel):
|
|||||||
)
|
)
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=50,
|
max_length=50,
|
||||||
choices=CableStatusChoices,
|
choices=LinkStatusChoices,
|
||||||
default=CableStatusChoices.STATUS_CONNECTED
|
default=LinkStatusChoices.STATUS_CONNECTED
|
||||||
)
|
)
|
||||||
label = models.CharField(
|
label = models.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
@ -285,7 +285,7 @@ class Cable(PrimaryModel):
|
|||||||
self._pk = self.pk
|
self._pk = self.pk
|
||||||
|
|
||||||
def get_status_class(self):
|
def get_status_class(self):
|
||||||
return CableStatusChoices.CSS_CLASSES.get(self.status)
|
return LinkStatusChoices.CSS_CLASSES.get(self.status)
|
||||||
|
|
||||||
def get_compatible_types(self):
|
def get_compatible_types(self):
|
||||||
"""
|
"""
|
||||||
@ -390,7 +390,7 @@ class CablePath(BigIDModel):
|
|||||||
|
|
||||||
node = origin
|
node = origin
|
||||||
while node.link is not None:
|
while node.link is not None:
|
||||||
if hasattr(node.link, 'status') and node.link.status != CableStatusChoices.STATUS_CONNECTED:
|
if hasattr(node.link, 'status') and node.link.status != LinkStatusChoices.STATUS_CONNECTED:
|
||||||
is_active = False
|
is_active = False
|
||||||
|
|
||||||
# Follow the link to its far-end termination
|
# Follow the link to its far-end termination
|
||||||
|
@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.db.models.signals import post_save, post_delete, pre_delete
|
from django.db.models.signals import post_save, post_delete, pre_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from .choices import CableStatusChoices
|
from .choices import LinkStatusChoices
|
||||||
from .models import Cable, CablePath, Device, PathEndpoint, PowerPanel, Rack, Location, VirtualChassis
|
from .models import Cable, CablePath, Device, PathEndpoint, PowerPanel, Rack, Location, VirtualChassis
|
||||||
from .utils import create_cablepath, rebuild_paths
|
from .utils import create_cablepath, rebuild_paths
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ def update_connected_endpoints(instance, created, raw=False, **kwargs):
|
|||||||
# We currently don't support modifying either termination of an existing Cable. (This
|
# We currently don't support modifying either termination of an existing Cable. (This
|
||||||
# may change in the future.) However, we do need to capture status changes and update
|
# may change in the future.) However, we do need to capture status changes and update
|
||||||
# any CablePaths accordingly.
|
# any CablePaths accordingly.
|
||||||
if instance.status != CableStatusChoices.STATUS_CONNECTED:
|
if instance.status != LinkStatusChoices.STATUS_CONNECTED:
|
||||||
CablePath.objects.filter(path__contains=instance).update(is_active=False)
|
CablePath.objects.filter(path__contains=instance).update(is_active=False)
|
||||||
else:
|
else:
|
||||||
rebuild_paths(instance)
|
rebuild_paths(instance)
|
||||||
|
@ -2,7 +2,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
from dcim.choices import CableStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from dcim.utils import object_to_path_node
|
from dcim.utils import object_to_path_node
|
||||||
|
|
||||||
@ -1142,7 +1142,7 @@ class CablePathTestCase(TestCase):
|
|||||||
self.assertEqual(CablePath.objects.count(), 2)
|
self.assertEqual(CablePath.objects.count(), 2)
|
||||||
|
|
||||||
# Change cable 2's status to "planned"
|
# Change cable 2's status to "planned"
|
||||||
cable2.status = CableStatusChoices.STATUS_PLANNED
|
cable2.status = LinkStatusChoices.STATUS_PLANNED
|
||||||
cable2.save()
|
cable2.save()
|
||||||
self.assertPathExists(
|
self.assertPathExists(
|
||||||
origin=interface1,
|
origin=interface1,
|
||||||
@ -1160,7 +1160,7 @@ class CablePathTestCase(TestCase):
|
|||||||
|
|
||||||
# Change cable 2's status to "connected"
|
# Change cable 2's status to "connected"
|
||||||
cable2 = Cable.objects.get(pk=cable2.pk)
|
cable2 = Cable.objects.get(pk=cable2.pk)
|
||||||
cable2.status = CableStatusChoices.STATUS_CONNECTED
|
cable2.status = LinkStatusChoices.STATUS_CONNECTED
|
||||||
cable2.save()
|
cable2.save()
|
||||||
self.assertPathExists(
|
self.assertPathExists(
|
||||||
origin=interface1,
|
origin=interface1,
|
||||||
|
@ -2855,12 +2855,12 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
console_server_port = ConsoleServerPort.objects.create(device=devices[0], name='Console Server Port 1')
|
console_server_port = ConsoleServerPort.objects.create(device=devices[0], name='Console Server Port 1')
|
||||||
|
|
||||||
# Cables
|
# Cables
|
||||||
Cable(termination_a=interfaces[1], termination_b=interfaces[2], label='Cable 1', type=CableTypeChoices.TYPE_CAT3, status=CableStatusChoices.STATUS_CONNECTED, color='aa1409', length=10, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
Cable(termination_a=interfaces[1], termination_b=interfaces[2], label='Cable 1', type=CableTypeChoices.TYPE_CAT3, status=LinkStatusChoices.STATUS_CONNECTED, color='aa1409', length=10, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
||||||
Cable(termination_a=interfaces[3], termination_b=interfaces[4], label='Cable 2', type=CableTypeChoices.TYPE_CAT3, status=CableStatusChoices.STATUS_CONNECTED, color='aa1409', length=20, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
Cable(termination_a=interfaces[3], termination_b=interfaces[4], label='Cable 2', type=CableTypeChoices.TYPE_CAT3, status=LinkStatusChoices.STATUS_CONNECTED, color='aa1409', length=20, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
||||||
Cable(termination_a=interfaces[5], termination_b=interfaces[6], label='Cable 3', type=CableTypeChoices.TYPE_CAT5E, status=CableStatusChoices.STATUS_CONNECTED, color='f44336', length=30, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
Cable(termination_a=interfaces[5], termination_b=interfaces[6], label='Cable 3', type=CableTypeChoices.TYPE_CAT5E, status=LinkStatusChoices.STATUS_CONNECTED, color='f44336', length=30, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
||||||
Cable(termination_a=interfaces[7], termination_b=interfaces[8], label='Cable 4', type=CableTypeChoices.TYPE_CAT5E, status=CableStatusChoices.STATUS_PLANNED, color='f44336', length=40, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
Cable(termination_a=interfaces[7], termination_b=interfaces[8], label='Cable 4', type=CableTypeChoices.TYPE_CAT5E, status=LinkStatusChoices.STATUS_PLANNED, color='f44336', length=40, length_unit=CableLengthUnitChoices.UNIT_FOOT).save()
|
||||||
Cable(termination_a=interfaces[9], termination_b=interfaces[10], label='Cable 5', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=10, length_unit=CableLengthUnitChoices.UNIT_METER).save()
|
Cable(termination_a=interfaces[9], termination_b=interfaces[10], label='Cable 5', type=CableTypeChoices.TYPE_CAT6, status=LinkStatusChoices.STATUS_PLANNED, color='e91e63', length=10, length_unit=CableLengthUnitChoices.UNIT_METER).save()
|
||||||
Cable(termination_a=interfaces[11], termination_b=interfaces[0], label='Cable 6', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=20, length_unit=CableLengthUnitChoices.UNIT_METER).save()
|
Cable(termination_a=interfaces[11], termination_b=interfaces[0], label='Cable 6', type=CableTypeChoices.TYPE_CAT6, status=LinkStatusChoices.STATUS_PLANNED, color='e91e63', length=20, length_unit=CableLengthUnitChoices.UNIT_METER).save()
|
||||||
Cable(termination_a=console_port, termination_b=console_server_port, label='Cable 7').save()
|
Cable(termination_a=console_port, termination_b=console_server_port, label='Cable 7').save()
|
||||||
|
|
||||||
def test_label(self):
|
def test_label(self):
|
||||||
@ -2880,9 +2880,9 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
def test_status(self):
|
def test_status(self):
|
||||||
params = {'status': [CableStatusChoices.STATUS_CONNECTED]}
|
params = {'status': [LinkStatusChoices.STATUS_CONNECTED]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
params = {'status': [CableStatusChoices.STATUS_PLANNED]}
|
params = {'status': [LinkStatusChoices.STATUS_PLANNED]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||||
|
|
||||||
def test_color(self):
|
def test_color(self):
|
||||||
|
@ -1813,7 +1813,7 @@ class CableTestCase(
|
|||||||
'termination_b_type': interface_ct.pk,
|
'termination_b_type': interface_ct.pk,
|
||||||
'termination_b_id': interfaces[3].pk,
|
'termination_b_id': interfaces[3].pk,
|
||||||
'type': CableTypeChoices.TYPE_CAT6,
|
'type': CableTypeChoices.TYPE_CAT6,
|
||||||
'status': CableStatusChoices.STATUS_PLANNED,
|
'status': LinkStatusChoices.STATUS_PLANNED,
|
||||||
'label': 'Label',
|
'label': 'Label',
|
||||||
'color': 'c0c0c0',
|
'color': 'c0c0c0',
|
||||||
'length': 100,
|
'length': 100,
|
||||||
@ -1830,7 +1830,7 @@ class CableTestCase(
|
|||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'type': CableTypeChoices.TYPE_CAT5E,
|
'type': CableTypeChoices.TYPE_CAT5E,
|
||||||
'status': CableStatusChoices.STATUS_CONNECTED,
|
'status': LinkStatusChoices.STATUS_CONNECTED,
|
||||||
'label': 'New label',
|
'label': 'New label',
|
||||||
'color': '00ff00',
|
'color': '00ff00',
|
||||||
'length': 50,
|
'length': 50,
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
<h5 class="card-header">Link Properties</h5>
|
<h5 class="card-header">Link Properties</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table class="table table-hover attr-table">
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Status</th>
|
||||||
|
<td>{{ object.get_status_display }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">SSID</th>
|
<th scope="row">SSID</th>
|
||||||
<td>{{ object.ssid|placeholder }}</td>
|
<td>{{ object.ssid|placeholder }}</td>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.api.serializers import NestedInterfaceSerializer
|
from dcim.api.serializers import NestedInterfaceSerializer
|
||||||
from ipam.api.serializers import NestedVLANSerializer
|
from ipam.api.serializers import NestedVLANSerializer
|
||||||
|
from netbox.api import ChoiceField
|
||||||
from netbox.api.serializers import PrimaryModelSerializer
|
from netbox.api.serializers import PrimaryModelSerializer
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
from .nested_serializers import *
|
from .nested_serializers import *
|
||||||
@ -25,11 +27,12 @@ class WirelessLANSerializer(PrimaryModelSerializer):
|
|||||||
|
|
||||||
class WirelessLinkSerializer(PrimaryModelSerializer):
|
class WirelessLinkSerializer(PrimaryModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
|
||||||
|
status = ChoiceField(choices=LinkStatusChoices, required=False)
|
||||||
interface_a = NestedInterfaceSerializer()
|
interface_a = NestedInterfaceSerializer()
|
||||||
interface_b = NestedInterfaceSerializer()
|
interface_b = NestedInterfaceSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLink
|
model = WirelessLink
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'description',
|
'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'description',
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import django_filters
|
import django_filters
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from dcim.choices import LinkStatusChoices
|
||||||
from extras.filters import TagFilter
|
from extras.filters import TagFilter
|
||||||
from netbox.filtersets import PrimaryModelFilterSet
|
from netbox.filtersets import PrimaryModelFilterSet
|
||||||
from .models import *
|
from .models import *
|
||||||
@ -37,6 +38,9 @@ class WirelessLinkFilterSet(PrimaryModelFilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=LinkStatusChoices
|
||||||
|
)
|
||||||
tag = TagFilter()
|
tag = TagFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from dcim.models import *
|
from dcim.choices import LinkStatusChoices
|
||||||
from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
|
from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
|
||||||
from ipam.models import VLAN
|
from ipam.models import VLAN
|
||||||
from utilities.forms import BootstrapMixin, DynamicModelChoiceField
|
from utilities.forms import BootstrapMixin, DynamicModelChoiceField
|
||||||
from wireless.constants import SSID_MAX_LENGTH
|
from wireless.constants import SSID_MAX_LENGTH
|
||||||
|
from wireless.models import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'WirelessLANBulkEditForm',
|
'WirelessLANBulkEditForm',
|
||||||
@ -14,7 +15,7 @@ __all__ = (
|
|||||||
|
|
||||||
class WirelessLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
|
class WirelessLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(
|
pk = forms.ModelMultipleChoiceField(
|
||||||
queryset=PowerFeed.objects.all(),
|
queryset=WirelessLAN.objects.all(),
|
||||||
widget=forms.MultipleHiddenInput
|
widget=forms.MultipleHiddenInput
|
||||||
)
|
)
|
||||||
vlan = DynamicModelChoiceField(
|
vlan = DynamicModelChoiceField(
|
||||||
@ -35,13 +36,17 @@ class WirelessLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldMode
|
|||||||
|
|
||||||
class WirelessLinkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
|
class WirelessLinkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(
|
pk = forms.ModelMultipleChoiceField(
|
||||||
queryset=PowerFeed.objects.all(),
|
queryset=WirelessLink.objects.all(),
|
||||||
widget=forms.MultipleHiddenInput
|
widget=forms.MultipleHiddenInput
|
||||||
)
|
)
|
||||||
ssid = forms.CharField(
|
ssid = forms.CharField(
|
||||||
max_length=SSID_MAX_LENGTH,
|
max_length=SSID_MAX_LENGTH,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
status = forms.ChoiceField(
|
||||||
|
choices=LinkStatusChoices,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
from extras.forms import CustomFieldModelCSVForm
|
from extras.forms import CustomFieldModelCSVForm
|
||||||
from ipam.models import VLAN
|
from ipam.models import VLAN
|
||||||
from utilities.forms import CSVModelChoiceField
|
from utilities.forms import CSVChoiceField, CSVModelChoiceField
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -23,6 +24,10 @@ class WirelessLANCSVForm(CustomFieldModelCSVForm):
|
|||||||
|
|
||||||
|
|
||||||
class WirelessLinkCSVForm(CustomFieldModelCSVForm):
|
class WirelessLinkCSVForm(CustomFieldModelCSVForm):
|
||||||
|
status = CSVChoiceField(
|
||||||
|
choices=LinkStatusChoices,
|
||||||
|
help_text='Connection status'
|
||||||
|
)
|
||||||
interface_a = CSVModelChoiceField(
|
interface_a = CSVModelChoiceField(
|
||||||
queryset=Interface.objects.all()
|
queryset=Interface.objects.all()
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from dcim.choices import LinkStatusChoices
|
||||||
from extras.forms import CustomFieldModelFilterForm
|
from extras.forms import CustomFieldModelFilterForm
|
||||||
from utilities.forms import BootstrapMixin, TagFilterField
|
from utilities.forms import add_blank_choice, BootstrapMixin, StaticSelect, TagFilterField
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -42,4 +43,9 @@ class WirelessLinkFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='SSID'
|
label='SSID'
|
||||||
)
|
)
|
||||||
|
status = forms.ChoiceField(
|
||||||
|
required=False,
|
||||||
|
choices=add_blank_choice(LinkStatusChoices),
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
@ -2,7 +2,7 @@ from dcim.models import Interface
|
|||||||
from extras.forms import CustomFieldModelForm
|
from extras.forms import CustomFieldModelForm
|
||||||
from extras.models import Tag
|
from extras.models import Tag
|
||||||
from ipam.models import VLAN
|
from ipam.models import VLAN
|
||||||
from utilities.forms import BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
from utilities.forms import BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -55,5 +55,8 @@ class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLink
|
model = WirelessLink
|
||||||
fields = [
|
fields = [
|
||||||
'interface_a', 'interface_b', 'ssid', 'description', 'tags',
|
'interface_a', 'interface_b', 'status', 'ssid', 'description', 'tags',
|
||||||
]
|
]
|
||||||
|
widgets = {
|
||||||
|
'status': StaticSelect,
|
||||||
|
}
|
||||||
|
@ -42,6 +42,7 @@ class Migration(migrations.Migration):
|
|||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('ssid', models.CharField(blank=True, max_length=32)),
|
('ssid', models.CharField(blank=True, max_length=32)),
|
||||||
|
('status', models.CharField(default='connected', max_length=50)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
('_interface_a_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')),
|
('_interface_a_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')),
|
||||||
('_interface_b_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')),
|
('_interface_b_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')),
|
||||||
|
@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.constants import WIRELESS_IFACE_TYPES
|
from dcim.constants import WIRELESS_IFACE_TYPES
|
||||||
from extras.utils import extras_features
|
from extras.utils import extras_features
|
||||||
from netbox.models import BigIDModel, PrimaryModel
|
from netbox.models import BigIDModel, PrimaryModel
|
||||||
@ -70,6 +71,11 @@ class WirelessLink(PrimaryModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
verbose_name='SSID'
|
verbose_name='SSID'
|
||||||
)
|
)
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=LinkStatusChoices,
|
||||||
|
default=LinkStatusChoices.STATUS_CONNECTED
|
||||||
|
)
|
||||||
description = models.CharField(
|
description = models.CharField(
|
||||||
max_length=200,
|
max_length=200,
|
||||||
blank=True
|
blank=True
|
||||||
@ -94,6 +100,8 @@ class WirelessLink(PrimaryModel):
|
|||||||
|
|
||||||
objects = RestrictedQuerySet.as_manager()
|
objects = RestrictedQuerySet.as_manager()
|
||||||
|
|
||||||
|
clone_fields = ('ssid', 'status')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['pk']
|
ordering = ['pk']
|
||||||
unique_together = ('interface_a', 'interface_b')
|
unique_together = ('interface_a', 'interface_b')
|
||||||
@ -104,6 +112,9 @@ class WirelessLink(PrimaryModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('wireless:wirelesslink', args=[self.pk])
|
return reverse('wireless:wirelesslink', args=[self.pk])
|
||||||
|
|
||||||
|
def get_status_class(self):
|
||||||
|
return LinkStatusChoices.CSS_CLASSES.get(self.status)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
# Validate interface types
|
# Validate interface types
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
from utilities.tables import BaseTable, TagColumn, ToggleColumn
|
from utilities.tables import BaseTable, ChoiceFieldColumn, TagColumn, ToggleColumn
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'WirelessLANTable',
|
'WirelessLANTable',
|
||||||
@ -30,6 +30,7 @@ class WirelessLinkTable(BaseTable):
|
|||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name='ID'
|
verbose_name='ID'
|
||||||
)
|
)
|
||||||
|
status = ChoiceFieldColumn()
|
||||||
interface_a = tables.Column(
|
interface_a = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -42,5 +43,5 @@ class WirelessLinkTable(BaseTable):
|
|||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = WirelessLink
|
model = WirelessLink
|
||||||
fields = ('pk', 'id', 'interface_a', 'interface_b', 'ssid', 'description')
|
fields = ('pk', 'id', 'status', 'interface_a', 'interface_b', 'ssid', 'description')
|
||||||
default_columns = ('pk', 'id', 'interface_a', 'interface_b', 'ssid', 'description')
|
default_columns = ('pk', 'id', 'status', 'interface_a', 'interface_b', 'ssid', 'description')
|
||||||
|
Loading…
Reference in New Issue
Block a user