mirror of
				https://github.com/netbox-community/netbox.git
				synced 2024-05-10 07:54:54 +00:00 
			
		
		
		
	Merge v3.1.9
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@ body:
 | 
			
		||||
    attributes:
 | 
			
		||||
      label: NetBox version
 | 
			
		||||
      description: What version of NetBox are you currently running?
 | 
			
		||||
      placeholder: v3.1.8
 | 
			
		||||
      placeholder: v3.1.9
 | 
			
		||||
    validations:
 | 
			
		||||
      required: true
 | 
			
		||||
  - type: dropdown
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature_request.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature_request.yaml
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@ body:
 | 
			
		||||
    attributes:
 | 
			
		||||
      label: NetBox version
 | 
			
		||||
      description: What version of NetBox are you currently running?
 | 
			
		||||
      placeholder: v3.1.8
 | 
			
		||||
      placeholder: v3.1.9
 | 
			
		||||
    validations:
 | 
			
		||||
      required: true
 | 
			
		||||
  - type: dropdown
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
  <img src="https://raw.githubusercontent.com/netbox-community/netbox/develop/docs/netbox_logo.svg" width="400" alt="NetBox logo" />
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
:loudspeaker: The **[2022 NetBox community survey](https://forms.gle/KR8YbR8GiJ9EYXM28)** is now open! We collect this feedback and demographic data from NetBox users around the world to help shape the project's long-term development goals. Please take a few minutes to share your responses!
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
NetBox is an infrastructure resource modeling (IRM) tool designed to empower
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
{style="height: 100px; margin-bottom: 3em"}
 | 
			
		||||
 | 
			
		||||
:loudspeaker: The **[2022 NetBox community survey](https://forms.gle/KR8YbR8GiJ9EYXM28)** is now open! We collect this feedback and demographic data from NetBox users around the world to help shape the project's long-term development goals. Please take a few minutes to share your responses!
 | 
			
		||||
 | 
			
		||||
# What is NetBox?
 | 
			
		||||
 | 
			
		||||
NetBox is an infrastructure resource modeling (IRM) application designed to empower network automation. Initially conceived by the network engineering team at [DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically to address the needs of network and infrastructure engineers. NetBox is made available as open source under the Apache 2 license. It encompasses the following aspects of network management:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,20 @@
 | 
			
		||||
# NetBox v3.1
 | 
			
		||||
 | 
			
		||||
## v3.1.9 (FUTURE)
 | 
			
		||||
## v3.1.10 (FUTURE)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## v3.1.9 (2022-03-07)
 | 
			
		||||
 | 
			
		||||
### Enhancements
 | 
			
		||||
 | 
			
		||||
* [#8594](https://github.com/netbox-community/netbox/issues/8594) - Enable filtering by exact description match for all applicable models
 | 
			
		||||
* [#8629](https://github.com/netbox-community/netbox/issues/8629) - Add description to tag table search function
 | 
			
		||||
* [#8664](https://github.com/netbox-community/netbox/issues/8664) - Show assigned ASNs/sites under list views
 | 
			
		||||
* [#8736](https://github.com/netbox-community/netbox/issues/8736) - Add PC and UPC fiber end faces for LC/SC/LSH port types
 | 
			
		||||
* [#8758](https://github.com/netbox-community/netbox/issues/8758) - Allow empty string substitution when renaming objects in bulk
 | 
			
		||||
* [#8762](https://github.com/netbox-community/netbox/issues/8762) - Link to rack elevations list from site view
 | 
			
		||||
* [#8766](https://github.com/netbox-community/netbox/issues/8766) - Add SCTP to service protocols list
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +23,11 @@
 | 
			
		||||
* [#8674](https://github.com/netbox-community/netbox/issues/8674) - Fix rendering of tabbed content in documentation
 | 
			
		||||
* [#8710](https://github.com/netbox-community/netbox/issues/8710) - Fix dynamic scope selection form fields when creating a VLAN group
 | 
			
		||||
* [#8713](https://github.com/netbox-community/netbox/issues/8713) - Restore missing "add" button on services list view
 | 
			
		||||
* [#8715](https://github.com/netbox-community/netbox/issues/8715) - Avoid returning multiple objects when restricting querysets using multiple tags in permissions
 | 
			
		||||
* [#8717](https://github.com/netbox-community/netbox/issues/8717) - Fix redirection after bulk edit/delete of prefixes from aggregate view
 | 
			
		||||
* [#8724](https://github.com/netbox-community/netbox/issues/8724) - Fix exception during device import with invalid device type
 | 
			
		||||
* [#8807](https://github.com/netbox-community/netbox/issues/8807) - Correct REST API URL for FHRP group assignments
 | 
			
		||||
* [#8808](https://github.com/netbox-community/netbox/issues/8808) - Fix members count under FHRP group list
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,11 +8,13 @@ theme:
 | 
			
		||||
  icon:
 | 
			
		||||
    repo: fontawesome/brands/github
 | 
			
		||||
  palette:
 | 
			
		||||
    - scheme: default
 | 
			
		||||
    - media: "(prefers-color-scheme: light)"
 | 
			
		||||
      scheme: default
 | 
			
		||||
      toggle:
 | 
			
		||||
        icon: material/lightbulb-outline
 | 
			
		||||
        name: Switch to Dark Mode
 | 
			
		||||
    - scheme: slate
 | 
			
		||||
    - media: "(prefers-color-scheme: dark)"
 | 
			
		||||
      scheme: slate
 | 
			
		||||
      toggle:
 | 
			
		||||
        icon: material/lightbulb
 | 
			
		||||
        name: Switch to Light Mode
 | 
			
		||||
 
 | 
			
		||||
@@ -1003,13 +1003,19 @@ class PortTypeChoices(ChoiceSet):
 | 
			
		||||
    TYPE_MRJ21 = 'mrj21'
 | 
			
		||||
    TYPE_ST = 'st'
 | 
			
		||||
    TYPE_SC = 'sc'
 | 
			
		||||
    TYPE_SC_PC = 'sc-pc'
 | 
			
		||||
    TYPE_SC_UPC = 'sc-upc'
 | 
			
		||||
    TYPE_SC_APC = 'sc-apc'
 | 
			
		||||
    TYPE_FC = 'fc'
 | 
			
		||||
    TYPE_LC = 'lc'
 | 
			
		||||
    TYPE_LC_PC = 'lc-pc'
 | 
			
		||||
    TYPE_LC_UPC = 'lc-upc'
 | 
			
		||||
    TYPE_LC_APC = 'lc-apc'
 | 
			
		||||
    TYPE_MTRJ = 'mtrj'
 | 
			
		||||
    TYPE_MPO = 'mpo'
 | 
			
		||||
    TYPE_LSH = 'lsh'
 | 
			
		||||
    TYPE_LSH_PC = 'lsh-pc'
 | 
			
		||||
    TYPE_LSH_UPC = 'lsh-upc'
 | 
			
		||||
    TYPE_LSH_APC = 'lsh-apc'
 | 
			
		||||
    TYPE_SPLICE = 'splice'
 | 
			
		||||
    TYPE_CS = 'cs'
 | 
			
		||||
@@ -1049,12 +1055,18 @@ class PortTypeChoices(ChoiceSet):
 | 
			
		||||
            (
 | 
			
		||||
                (TYPE_FC, 'FC'),
 | 
			
		||||
                (TYPE_LC, 'LC'),
 | 
			
		||||
                (TYPE_LC_PC, 'LC/PC'),
 | 
			
		||||
                (TYPE_LC_UPC, 'LC/UPC'),
 | 
			
		||||
                (TYPE_LC_APC, 'LC/APC'),
 | 
			
		||||
                (TYPE_LSH, 'LSH'),
 | 
			
		||||
                (TYPE_LSH_PC, 'LSH/PC'),
 | 
			
		||||
                (TYPE_LSH_UPC, 'LSH/UPC'),
 | 
			
		||||
                (TYPE_LSH_APC, 'LSH/APC'),
 | 
			
		||||
                (TYPE_MPO, 'MPO'),
 | 
			
		||||
                (TYPE_MTRJ, 'MTRJ'),
 | 
			
		||||
                (TYPE_SC, 'SC'),
 | 
			
		||||
                (TYPE_SC_PC, 'SC/PC'),
 | 
			
		||||
                (TYPE_SC_UPC, 'SC/UPC'),
 | 
			
		||||
                (TYPE_SC_APC, 'SC/APC'),
 | 
			
		||||
                (TYPE_ST, 'ST'),
 | 
			
		||||
                (TYPE_CS, 'CS'),
 | 
			
		||||
 
 | 
			
		||||
@@ -804,10 +804,11 @@ class Device(NetBoxModel, ConfigContextModel):
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
        # Prevent 0U devices from being assigned to a specific position
 | 
			
		||||
        if self.position and self.device_type.u_height == 0:
 | 
			
		||||
            raise ValidationError({
 | 
			
		||||
                'position': f"A U0 device type ({self.device_type}) cannot be assigned to a rack position."
 | 
			
		||||
            })
 | 
			
		||||
        if hasattr(self, 'device_type'):
 | 
			
		||||
            if self.position and self.device_type.u_height == 0:
 | 
			
		||||
                raise ValidationError({
 | 
			
		||||
                    'position': f"A U0 device type ({self.device_type}) cannot be assigned to a rack position."
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
        if self.rack:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,10 @@ class SiteTable(NetBoxTable):
 | 
			
		||||
        accessor=tables.A('asns__count'),
 | 
			
		||||
        viewname='ipam:asn_list',
 | 
			
		||||
        url_params={'site_id': 'pk'},
 | 
			
		||||
        verbose_name='ASN Count'
 | 
			
		||||
    )
 | 
			
		||||
    asns = tables.ManyToManyColumn(
 | 
			
		||||
        linkify_item=True,
 | 
			
		||||
        verbose_name='ASNs'
 | 
			
		||||
    )
 | 
			
		||||
    tenant = TenantColumn()
 | 
			
		||||
@@ -93,9 +97,9 @@ class SiteTable(NetBoxTable):
 | 
			
		||||
    class Meta(NetBoxTable.Meta):
 | 
			
		||||
        model = Site
 | 
			
		||||
        fields = (
 | 
			
		||||
            'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asn_count', 'time_zone',
 | 
			
		||||
            'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags',
 | 
			
		||||
            'created', 'last_updated', 'actions',
 | 
			
		||||
            'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asns', 'asn_count',
 | 
			
		||||
            'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments',
 | 
			
		||||
            'tags', 'created', 'last_updated', 'actions',
 | 
			
		||||
        )
 | 
			
		||||
        default_columns = ('pk', 'name', 'status', 'facility', 'region', 'group', 'tenant', 'description')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -126,7 +126,7 @@ class FHRPGroupSerializer(PrimaryModelSerializer):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FHRPGroupAssignmentSerializer(PrimaryModelSerializer):
 | 
			
		||||
    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactassignment-detail')
 | 
			
		||||
    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail')
 | 
			
		||||
    group = NestedFHRPGroupSerializer()
 | 
			
		||||
    interface_type = ContentTypeField(
 | 
			
		||||
        queryset=ContentType.objects.all()
 | 
			
		||||
 
 | 
			
		||||
@@ -155,8 +155,10 @@ class ServiceProtocolChoices(ChoiceSet):
 | 
			
		||||
 | 
			
		||||
    PROTOCOL_TCP = 'tcp'
 | 
			
		||||
    PROTOCOL_UDP = 'udp'
 | 
			
		||||
    PROTOCOL_SCTP = 'sctp'
 | 
			
		||||
 | 
			
		||||
    CHOICES = (
 | 
			
		||||
        (PROTOCOL_TCP, 'TCP'),
 | 
			
		||||
        (PROTOCOL_UDP, 'UDP'),
 | 
			
		||||
        (PROTOCOL_SCTP, 'SCTP'),
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@ class FHRPGroupTable(NetBoxTable):
 | 
			
		||||
        orderable=False,
 | 
			
		||||
        verbose_name='IP Addresses'
 | 
			
		||||
    )
 | 
			
		||||
    interface_count = tables.Column(
 | 
			
		||||
        verbose_name='Interfaces'
 | 
			
		||||
    member_count = tables.Column(
 | 
			
		||||
        verbose_name='Members'
 | 
			
		||||
    )
 | 
			
		||||
    tags = columns.TagColumn(
 | 
			
		||||
        url_name='ipam:fhrpgroup_list'
 | 
			
		||||
@@ -36,10 +36,10 @@ class FHRPGroupTable(NetBoxTable):
 | 
			
		||||
    class Meta(NetBoxTable.Meta):
 | 
			
		||||
        model = FHRPGroup
 | 
			
		||||
        fields = (
 | 
			
		||||
            'pk', 'group_id', 'protocol', 'auth_type', 'auth_key', 'description', 'ip_addresses', 'interface_count',
 | 
			
		||||
            'pk', 'group_id', 'protocol', 'auth_type', 'auth_key', 'description', 'ip_addresses', 'member_count',
 | 
			
		||||
            'tags', 'created', 'last_updated',
 | 
			
		||||
        )
 | 
			
		||||
        default_columns = ('pk', 'group_id', 'protocol', 'auth_type', 'description', 'ip_addresses', 'interface_count')
 | 
			
		||||
        default_columns = ('pk', 'group_id', 'protocol', 'auth_type', 'description', 'ip_addresses', 'member_count')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FHRPGroupAssignmentTable(NetBoxTable):
 | 
			
		||||
 
 | 
			
		||||
@@ -112,6 +112,10 @@ class ASNTable(NetBoxTable):
 | 
			
		||||
    site_count = columns.LinkedCountColumn(
 | 
			
		||||
        viewname='dcim:site_list',
 | 
			
		||||
        url_params={'asn_id': 'pk'},
 | 
			
		||||
        verbose_name='Site Count'
 | 
			
		||||
    )
 | 
			
		||||
    sites = tables.ManyToManyColumn(
 | 
			
		||||
        linkify_item=True,
 | 
			
		||||
        verbose_name='Sites'
 | 
			
		||||
    )
 | 
			
		||||
    tenant = TenantColumn()
 | 
			
		||||
@@ -122,8 +126,8 @@ class ASNTable(NetBoxTable):
 | 
			
		||||
    class Meta(NetBoxTable.Meta):
 | 
			
		||||
        model = ASN
 | 
			
		||||
        fields = (
 | 
			
		||||
            'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'tenant', 'description', 'created', 'last_updated',
 | 
			
		||||
            'actions',
 | 
			
		||||
            'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'tenant', 'description', 'sites', 'tags', 'created',
 | 
			
		||||
            'last_updated', 'actions',
 | 
			
		||||
        )
 | 
			
		||||
        default_columns = ('pk', 'asn', 'rir', 'site_count', 'sites', 'description', 'tenant')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -116,52 +116,54 @@ Blocks:
 | 
			
		||||
 | 
			
		||||
        {# Page footer #}
 | 
			
		||||
        <footer class="footer container-fluid">
 | 
			
		||||
          <div class="row align-items-center justify-content-between mx-0">
 | 
			
		||||
          {% block footer %}
 | 
			
		||||
            <div class="row align-items-center justify-content-between mx-0">
 | 
			
		||||
 | 
			
		||||
            {# Docs & Community Links #}
 | 
			
		||||
            <div class="col-sm-12 col-md-auto fs-4 noprint">
 | 
			
		||||
              <nav class="nav justify-content-center justify-content-lg-start">
 | 
			
		||||
                {# Documentation #}
 | 
			
		||||
                <a type="button" class="nav-link" href="{% static 'docs/' %}" target="_blank">
 | 
			
		||||
                  <i title="Docs" class="mdi mdi-book-open-variant text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                </a>
 | 
			
		||||
              <div class="col-sm-12 col-md-auto fs-4 noprint">
 | 
			
		||||
                <nav class="nav justify-content-center justify-content-lg-start">
 | 
			
		||||
                  {% block footer_links %}
 | 
			
		||||
                    {# Documentation #}
 | 
			
		||||
                    <a type="button" class="nav-link" href="{% static 'docs/' %}" target="_blank">
 | 
			
		||||
                      <i title="Docs" class="mdi mdi-book-open-variant text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                {# REST API #}
 | 
			
		||||
                <a type="button" class="nav-link" href="{% url 'api-root' %}" target="_blank">
 | 
			
		||||
                  <i title="REST API" class="mdi mdi-cloud-braces text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                </a>
 | 
			
		||||
                    {# REST API #}
 | 
			
		||||
                    <a type="button" class="nav-link" href="{% url 'api-root' %}" target="_blank">
 | 
			
		||||
                      <i title="REST API" class="mdi mdi-cloud-braces text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                {# API docs #}
 | 
			
		||||
                <a type="button" class="nav-link" href="{% url 'api_docs' %}" target="_blank">
 | 
			
		||||
                  <i title="REST API documentation" class="mdi mdi-book text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                </a>
 | 
			
		||||
                    {# API docs #}
 | 
			
		||||
                    <a type="button" class="nav-link" href="{% url 'api_docs' %}" target="_blank">
 | 
			
		||||
                      <i title="REST API documentation" class="mdi mdi-book text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                {# GraphQL API #}
 | 
			
		||||
                {% if config.GRAPHQL_ENABLED %}
 | 
			
		||||
                  <a type="button" class="nav-link" href="{% url 'graphql' %}" target="_blank">
 | 
			
		||||
                    <i title="GraphQL API" class="mdi mdi-graphql text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                  </a>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                    {# GraphQL API #}
 | 
			
		||||
                    {% if config.GRAPHQL_ENABLED %}
 | 
			
		||||
                    <a type="button" class="nav-link" href="{% url 'graphql' %}" target="_blank">
 | 
			
		||||
                      <i title="GraphQL API" class="mdi mdi-graphql text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
 | 
			
		||||
                {# GitHub #}
 | 
			
		||||
                <a type="button" class="nav-link" href="https://github.com/netbox-community/netbox" target="_blank">
 | 
			
		||||
                  <i title="Source Code" class="mdi mdi-github text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                </a>
 | 
			
		||||
                    {# GitHub #}
 | 
			
		||||
                    <a type="button" class="nav-link" href="https://github.com/netbox-community/netbox" target="_blank">
 | 
			
		||||
                      <i title="Source Code" class="mdi mdi-github text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                    {# NetDev Slack #}
 | 
			
		||||
                    <a type="button" class="nav-link" href="https://netdev.chat/" target="_blank">
 | 
			
		||||
                      <i title="Community" class="mdi mdi-slack text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                    </a>
 | 
			
		||||
                  {% endblock footer_links %}
 | 
			
		||||
                </nav>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="col-sm-12 col-md-auto text-center text-lg-end text-muted">
 | 
			
		||||
                <span class="d-block d-md-inline">{% annotated_now %} {% now 'T' %}</span>
 | 
			
		||||
                <span class="ms-md-3 d-block d-md-inline">{{ settings.HOSTNAME }} (v{{ settings.VERSION }})</span>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
                {# NetDev Slack #}
 | 
			
		||||
                <a type="button" class="nav-link" href="https://netdev.chat/" target="_blank">
 | 
			
		||||
                  <i title="Community" class="mdi mdi-slack text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>
 | 
			
		||||
                </a>
 | 
			
		||||
              </nav>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {# System Info #}
 | 
			
		||||
            <div class="col-sm-12 col-md-auto text-center text-lg-end text-muted">
 | 
			
		||||
              <span class="d-block d-md-inline">{% annotated_now %} {% now 'T' %}</span>
 | 
			
		||||
              <span class="ms-md-3 d-block d-md-inline">{{ settings.HOSTNAME }} (v{{ settings.VERSION }})</span>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
          </div>
 | 
			
		||||
          {% endblock footer %}
 | 
			
		||||
        </footer>
 | 
			
		||||
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -131,42 +131,98 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col col-md-6">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <h5 class="card-header">Stats</h5>
 | 
			
		||||
        <h5 class="card-header">Related Objects</h5>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'dcim:location_list' %}?site_id={{ object.pk }}" class="btn {% if stats.location_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.location_count }}</a></h2>
 | 
			
		||||
              <p>Locations</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'dcim:rack_list' %}?site_id={{ object.pk }}" class="btn {% if stats.rack_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.rack_count }}</a></h2>
 | 
			
		||||
              <p>Racks</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'dcim:device_list' %}?site_id={{ object.pk }}" class="btn {% if stats.device_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.device_count }}</a></h2>
 | 
			
		||||
              <p>Devices</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'ipam:prefix_list' %}?site_id={{ object.pk }}" class="btn {% if stats.prefix_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.prefix_count }}</a></h2>
 | 
			
		||||
              <p>Prefixes</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'ipam:vlan_list' %}?site_id={{ object.pk }}" class="btn {% if stats.vlan_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.vlan_count }}</a></h2>
 | 
			
		||||
              <p>VLANs</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'circuits:circuit_list' %}?site_id={{ object.pk }}" class="btn {% if stats.circuit_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.circuit_count }}</a></h2>
 | 
			
		||||
              <p>Circuits</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'virtualization:virtualmachine_list' %}?site_id={{ object.pk }}" class="btn {% if stats.vm_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.vm_count }}</a></h2>
 | 
			
		||||
              <p>Virtual Machines</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col col-md-4 text-center">
 | 
			
		||||
              <h2><a href="{% url 'ipam:asn_list' %}?site_id={{ object.pk }}" class="btn {% if stats.asn_count %}btn-primary{% else %}btn-outline-dark{% endif %} btn-lg">{{ stats.asn_count }}</a></h2>
 | 
			
		||||
              <p>ASNs</p>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <table class="table table-hover attr-table">
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Locations</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.location_count %}
 | 
			
		||||
                  <a href="{% url 'dcim:location_list' %}?site_id={{ object.pk }}">{{ stats.location_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Racks</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.rack_count %}
 | 
			
		||||
                  <div class="dropdown">
 | 
			
		||||
                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
 | 
			
		||||
                      {{ stats.rack_count }}
 | 
			
		||||
                    </button>
 | 
			
		||||
                    <ul class="dropdown-menu">
 | 
			
		||||
                      <li><a class="dropdown-item" href="{% url 'dcim:rack_list' %}?site_id={{ object.pk }}">View Racks</a></li>
 | 
			
		||||
                      <li><a class="dropdown-item" href="{% url 'dcim:rack_elevation_list' %}?site_id={{ object.pk }}">View Elevations</a></li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                  </div>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Devices</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.device_count %}
 | 
			
		||||
                  <a href="{% url 'dcim:device_list' %}?site_id={{ object.pk }}">{{ stats.device_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Virtual Machines</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.vm_count %}
 | 
			
		||||
                  <a href="{% url 'virtualization:virtualmachine_list' %}?site_id={{ object.pk }}">{{ stats.vm_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Prefixes</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.prefix_count %}
 | 
			
		||||
                  <a href="{% url 'ipam:prefix_list' %}?site_id={{ object.pk }}">{{ stats.prefix_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">VLANs</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.vlan_count %}
 | 
			
		||||
                  <a href="{% url 'ipam:vlan_list' %}?site_id={{ object.pk }}">{{ stats.vlan_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">ASNs</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.asn_count %}
 | 
			
		||||
                  <a href="{% url 'ipam:asn_list' %}?site_id={{ object.pk }}">{{ stats.asn_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th scope="row">Circuits</th>
 | 
			
		||||
              <td class="text-end">
 | 
			
		||||
                {% if stats.circuit_count %}
 | 
			
		||||
                <a href="{% url 'circuits:circuit_list' %}?site_id={{ object.pk }}">{{ stats.circuit_count }}</a>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                  {{ ''|placeholder }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {% include 'inc/panels/contacts.html' %}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,18 @@
 | 
			
		||||
 | 
			
		||||
{% block title %}Search{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% block tabs %}
 | 
			
		||||
  <ul class="nav nav-tabs px-3">
 | 
			
		||||
    <li class="nav-item" role="presentation">
 | 
			
		||||
      <button class="nav-link active" type="button" role="tab">
 | 
			
		||||
        Results
 | 
			
		||||
      </button>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
{% endblock tabs %}
 | 
			
		||||
 | 
			
		||||
{% block content-wrapper %}
 | 
			
		||||
  <div class="tab-content">
 | 
			
		||||
    {% if request.GET.q %}
 | 
			
		||||
        {% if results %}
 | 
			
		||||
            <div class="row">
 | 
			
		||||
@@ -73,4 +84,5 @@
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
  </div>
 | 
			
		||||
{% endblock content-wrapper %}
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,9 @@ class BulkRenameForm(BootstrapMixin, forms.Form):
 | 
			
		||||
    An extendable form to be used for renaming objects in bulk.
 | 
			
		||||
    """
 | 
			
		||||
    find = forms.CharField()
 | 
			
		||||
    replace = forms.CharField()
 | 
			
		||||
    replace = forms.CharField(
 | 
			
		||||
        required=False
 | 
			
		||||
    )
 | 
			
		||||
    use_regex = forms.BooleanField(
 | 
			
		||||
        required=False,
 | 
			
		||||
        initial=True,
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,12 @@ class RestrictedQuerySet(QuerySet):
 | 
			
		||||
                    # Any permission with null constraints grants access to _all_ instances
 | 
			
		||||
                    attrs = Q()
 | 
			
		||||
                    break
 | 
			
		||||
            else:
 | 
			
		||||
                # for else, when no break
 | 
			
		||||
                # avoid duplicates when JOIN on many-to-many fields without using DISTINCT.
 | 
			
		||||
                # DISTINCT acts globally on the entire request, which may not be desirable.
 | 
			
		||||
                allowed_objects = self.model.objects.filter(attrs)
 | 
			
		||||
                attrs = Q(pk__in=allowed_objects)
 | 
			
		||||
            qs = self.filter(attrs)
 | 
			
		||||
 | 
			
		||||
        return qs
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ gunicorn==20.1.0
 | 
			
		||||
Jinja2==3.0.3
 | 
			
		||||
Markdown==3.3.6
 | 
			
		||||
markdown-include==0.6.0
 | 
			
		||||
mkdocs-material==8.1.11
 | 
			
		||||
mkdocs-material==8.2.5
 | 
			
		||||
mkdocstrings==0.17.0
 | 
			
		||||
netaddr==0.8.0
 | 
			
		||||
Pillow==9.0.1
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user