mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-19 18:18:43 -06:00
Compare commits
1 Commits
main
...
15801-vlan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f468b4bbf |
@@ -13,7 +13,6 @@ if TYPE_CHECKING:
|
|||||||
from netbox.graphql.filter_lookups import IntegerLookup
|
from netbox.graphql.filter_lookups import IntegerLookup
|
||||||
from extras.graphql.filters import ConfigTemplateFilter
|
from extras.graphql.filters import ConfigTemplateFilter
|
||||||
from ipam.graphql.filters import VLANFilter, VLANTranslationPolicyFilter
|
from ipam.graphql.filters import VLANFilter, VLANTranslationPolicyFilter
|
||||||
from dcim.graphql.filters import LocationFilter, RegionFilter, SiteFilter, SiteGroupFilter
|
|
||||||
from .filters import *
|
from .filters import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@@ -36,20 +35,6 @@ class ScopedFilterMixin:
|
|||||||
)
|
)
|
||||||
scope_id: ID | None = strawberry_django.filter_field()
|
scope_id: ID | None = strawberry_django.filter_field()
|
||||||
|
|
||||||
# Cached relations
|
|
||||||
_location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
|
|
||||||
strawberry_django.filter_field(name='location')
|
|
||||||
)
|
|
||||||
_region: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
|
|
||||||
strawberry_django.filter_field(name='region')
|
|
||||||
)
|
|
||||||
_site_group: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
|
|
||||||
strawberry_django.filter_field(name='site_group')
|
|
||||||
)
|
|
||||||
_site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
|
|
||||||
strawberry_django.filter_field(name='site')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ComponentModelFilterMixin:
|
class ComponentModelFilterMixin:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class RackDimensionsPanel(panels.ObjectAttributesPanel):
|
|||||||
outer_width = attrs.NumericAttr('outer_width', unit_accessor='get_outer_unit_display')
|
outer_width = attrs.NumericAttr('outer_width', unit_accessor='get_outer_unit_display')
|
||||||
outer_height = attrs.NumericAttr('outer_height', unit_accessor='get_outer_unit_display')
|
outer_height = attrs.NumericAttr('outer_height', unit_accessor='get_outer_unit_display')
|
||||||
outer_depth = attrs.NumericAttr('outer_depth', unit_accessor='get_outer_unit_display')
|
outer_depth = attrs.NumericAttr('outer_depth', unit_accessor='get_outer_unit_display')
|
||||||
mounting_depth = attrs.TextAttr('mounting_depth', format_string=_('{} millimeters'))
|
mounting_depth = attrs.TextAttr('mounting_depth', format_string='{} mm')
|
||||||
|
|
||||||
|
|
||||||
class RackNumberingPanel(panels.ObjectAttributesPanel):
|
class RackNumberingPanel(panels.ObjectAttributesPanel):
|
||||||
|
|||||||
@@ -4,17 +4,6 @@ from extras.choices import LogLevelChoices
|
|||||||
# Custom fields
|
# Custom fields
|
||||||
CUSTOMFIELD_EMPTY_VALUES = (None, '', [])
|
CUSTOMFIELD_EMPTY_VALUES = (None, '', [])
|
||||||
|
|
||||||
# ImageAttachment
|
|
||||||
IMAGE_ATTACHMENT_IMAGE_FORMATS = {
|
|
||||||
'avif': 'image/avif',
|
|
||||||
'bmp': 'image/bmp',
|
|
||||||
'gif': 'image/gif',
|
|
||||||
'jpeg': 'image/jpeg',
|
|
||||||
'jpg': 'image/jpeg',
|
|
||||||
'png': 'image/png',
|
|
||||||
'webp': 'image/webp',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Template Export
|
# Template Export
|
||||||
DEFAULT_MIME_TYPE = 'text/plain; charset=utf-8'
|
DEFAULT_MIME_TYPE = 'text/plain; charset=utf-8'
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from core.forms.mixins import SyncedDataMixin
|
from core.forms.mixins import SyncedDataMixin
|
||||||
from core.models import ObjectType
|
from core.models import ObjectType
|
||||||
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
|
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
|
||||||
from extras.constants import IMAGE_ATTACHMENT_IMAGE_FORMATS
|
|
||||||
from extras.choices import *
|
from extras.choices import *
|
||||||
from extras.models import *
|
from extras.models import *
|
||||||
from netbox.events import get_event_type_choices
|
from netbox.events import get_event_type_choices
|
||||||
@@ -785,11 +784,8 @@ class ImageAttachmentForm(forms.ModelForm):
|
|||||||
fields = [
|
fields = [
|
||||||
'image', 'name', 'description',
|
'image', 'name', 'description',
|
||||||
]
|
]
|
||||||
# Explicitly set 'image/avif' to support AVIF selection in Firefox
|
help_texts = {
|
||||||
widgets = {
|
'name': _("If no name is specified, the file name will be used.")
|
||||||
'image': forms.ClearableFileInput(
|
|
||||||
attrs={'accept': ','.join(sorted(set(IMAGE_ATTACHMENT_IMAGE_FORMATS.values())))}
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ from taggit.managers import _TaggableManager
|
|||||||
|
|
||||||
from netbox.context import current_request
|
from netbox.context import current_request
|
||||||
|
|
||||||
from .constants import IMAGE_ATTACHMENT_IMAGE_FORMATS
|
|
||||||
from .validators import CustomValidator
|
from .validators import CustomValidator
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@@ -79,7 +78,7 @@ def image_upload(instance, filename):
|
|||||||
"""
|
"""
|
||||||
upload_dir = 'image-attachments'
|
upload_dir = 'image-attachments'
|
||||||
default_filename = 'unnamed'
|
default_filename = 'unnamed'
|
||||||
allowed_img_extensions = IMAGE_ATTACHMENT_IMAGE_FORMATS.keys()
|
allowed_img_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png', 'webp')
|
||||||
|
|
||||||
# Normalize Windows paths and create a Path object.
|
# Normalize Windows paths and create a Path object.
|
||||||
normalized_filename = str(filename).replace('\\', '/')
|
normalized_filename = str(filename).replace('\\', '/')
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
|
|||||||
from virtualization.models import VMInterface
|
from virtualization.models import VMInterface
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from netbox.graphql.filter_lookups import BigIntegerLookup, IntegerLookup, IntegerRangeArrayLookup
|
from netbox.graphql.filter_lookups import IntegerLookup, IntegerRangeArrayLookup
|
||||||
from circuits.graphql.filters import ProviderFilter
|
from circuits.graphql.filters import ProviderFilter
|
||||||
from core.graphql.filters import ContentTypeFilter
|
from core.graphql.filters import ContentTypeFilter
|
||||||
from dcim.graphql.filters import SiteFilter
|
from dcim.graphql.filters import SiteFilter
|
||||||
@@ -53,7 +53,7 @@ __all__ = (
|
|||||||
class ASNFilter(TenancyFilterMixin, PrimaryModelFilter):
|
class ASNFilter(TenancyFilterMixin, PrimaryModelFilter):
|
||||||
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
|
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
|
||||||
rir_id: ID | None = strawberry_django.filter_field()
|
rir_id: ID | None = strawberry_django.filter_field()
|
||||||
asn: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
asn: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
sites: (
|
sites: (
|
||||||
@@ -70,10 +70,10 @@ class ASNRangeFilter(TenancyFilterMixin, OrganizationalModelFilter):
|
|||||||
slug: FilterLookup[str] | None = strawberry_django.filter_field()
|
slug: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||||
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
|
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
|
||||||
rir_id: ID | None = strawberry_django.filter_field()
|
rir_id: ID | None = strawberry_django.filter_field()
|
||||||
start: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
start: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
end: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
end: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from django_tables2.utils import Accessor
|
from django_tables2.utils import Accessor
|
||||||
|
|
||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
|
from dcim.tables.template_code import INTERFACE_LINKTERMINATION, LINKTERMINATION
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
|
from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
|
||||||
from tenancy.tables import TenancyColumnsMixin, TenantColumn
|
from tenancy.tables import TenancyColumnsMixin, TenantColumn
|
||||||
@@ -159,11 +160,26 @@ class VLANDevicesTable(VLANMembersTable):
|
|||||||
actions = columns.ActionsColumn(
|
actions = columns.ActionsColumn(
|
||||||
actions=('edit',)
|
actions=('edit',)
|
||||||
)
|
)
|
||||||
|
link_peer = columns.TemplateColumn(
|
||||||
|
accessor='link_peers',
|
||||||
|
template_code=LINKTERMINATION,
|
||||||
|
orderable=False,
|
||||||
|
verbose_name=_('Link Peers'),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Override PathEndpointTable.connection to accommodate virtual circuits
|
||||||
|
connection = columns.TemplateColumn(
|
||||||
|
accessor='_path__destinations',
|
||||||
|
template_code=INTERFACE_LINKTERMINATION,
|
||||||
|
orderable=False,
|
||||||
|
verbose_name=_('Connection'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = ('device', 'name', 'tagged', 'actions')
|
fields = ('device', 'name', 'link_peer', 'connection', 'tagged', 'actions')
|
||||||
exclude = ('id', )
|
default_columns = ('device', 'name', 'connection', 'tagged', 'actions')
|
||||||
|
exclude = ('id',)
|
||||||
|
|
||||||
|
|
||||||
class VLANVirtualMachinesTable(VLANMembersTable):
|
class VLANVirtualMachinesTable(VLANMembersTable):
|
||||||
|
|||||||
@@ -19,11 +19,8 @@ from strawberry_django import (
|
|||||||
process_filters,
|
process_filters,
|
||||||
)
|
)
|
||||||
|
|
||||||
from netbox.graphql.scalars import BigInt
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ArrayLookup',
|
'ArrayLookup',
|
||||||
'BigIntegerLookup',
|
|
||||||
'FloatArrayLookup',
|
'FloatArrayLookup',
|
||||||
'FloatLookup',
|
'FloatLookup',
|
||||||
'IntegerArrayLookup',
|
'IntegerArrayLookup',
|
||||||
@@ -81,29 +78,6 @@ class IntegerLookup:
|
|||||||
return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix)
|
return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix)
|
||||||
|
|
||||||
|
|
||||||
@strawberry.input(one_of=True, description='Lookup for BigInteger fields. Only one of the lookup fields can be set.')
|
|
||||||
class BigIntegerLookup:
|
|
||||||
filter_lookup: FilterLookup[BigInt] | None = strawberry_django.filter_field()
|
|
||||||
range_lookup: RangeLookup[BigInt] | None = strawberry_django.filter_field()
|
|
||||||
comparison_lookup: ComparisonFilterLookup[BigInt] | None = strawberry_django.filter_field()
|
|
||||||
|
|
||||||
def get_filter(self):
|
|
||||||
for field in self.__strawberry_definition__.fields:
|
|
||||||
value = getattr(self, field.name, None)
|
|
||||||
if value is not strawberry.UNSET:
|
|
||||||
return value
|
|
||||||
return None
|
|
||||||
|
|
||||||
@strawberry_django.filter_field
|
|
||||||
def filter(self, info: Info, queryset: QuerySet, prefix: DirectiveValue[str] = '') -> Tuple[QuerySet, Q]:
|
|
||||||
filters = self.get_filter()
|
|
||||||
|
|
||||||
if not filters:
|
|
||||||
return queryset, Q()
|
|
||||||
|
|
||||||
return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix)
|
|
||||||
|
|
||||||
|
|
||||||
@strawberry.input(one_of=True, description='Lookup for Float fields. Only one of the lookup fields can be set.')
|
@strawberry.input(one_of=True, description='Lookup for Float fields. Only one of the lookup fields can be set.')
|
||||||
class FloatLookup:
|
class FloatLookup:
|
||||||
filter_lookup: FilterLookup[float] | None = strawberry_django.filter_field()
|
filter_lookup: FilterLookup[float] | None = strawberry_django.filter_field()
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ import string
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
OBJECTPERMISSION_OBJECT_TYPES = (
|
OBJECTPERMISSION_OBJECT_TYPES = Q(
|
||||||
(Q(public=True) & ~Q(app_label='core', model='objecttype'))
|
~Q(app_label__in=['account', 'admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users']) |
|
||||||
| Q(app_label='core', model__in=['managedfile'])
|
Q(app_label='users', model__in=['objectpermission', 'token', 'group', 'user', 'owner'])
|
||||||
| Q(app_label='extras', model__in=['scriptmodule', 'taggeditem'])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
CONSTRAINT_TOKEN_USER = '$user'
|
CONSTRAINT_TOKEN_USER = '$user'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from vpn import models
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.graphql.filters import ContentTypeFilter
|
from core.graphql.filters import ContentTypeFilter
|
||||||
from ipam.graphql.filters import IPAddressFilter, RouteTargetFilter
|
from ipam.graphql.filters import IPAddressFilter, RouteTargetFilter
|
||||||
from netbox.graphql.filter_lookups import BigIntegerLookup, IntegerLookup
|
from netbox.graphql.filter_lookups import IntegerLookup
|
||||||
from .enums import *
|
from .enums import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@@ -75,7 +75,7 @@ class TunnelFilter(TenancyFilterMixin, PrimaryModelFilter):
|
|||||||
ipsec_profile: Annotated['IPSecProfileFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
|
ipsec_profile: Annotated['IPSecProfileFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
tunnel_id: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
tunnel_id: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
terminations: Annotated['TunnelTerminationFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
|
terminations: Annotated['TunnelTerminationFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
|
||||||
@@ -187,7 +187,7 @@ class L2VPNFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilter):
|
|||||||
type: BaseFilterLookup[Annotated['L2VPNTypeEnum', strawberry.lazy('vpn.graphql.enums')]] | None = (
|
type: BaseFilterLookup[Annotated['L2VPNTypeEnum', strawberry.lazy('vpn.graphql.enums')]] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
identifier: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
identifier: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
|
||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
import_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
|
import_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
|
||||||
|
|||||||
Reference in New Issue
Block a user