소스 검색

Merge branch 'main' into feature

Resolved conflicts:
- Dropped 4.7 deprecation shims (FutureWarning getattr/methods) re-introduced
  by main, which feature has already removed: pagination, constants, registry,
  forms utils/expandable, settings (Sentry), generic view mixins.
- dcim/signals.py: kept main's search-cache-on-VC-rename handler; dropped
  Prefix/Cluster/WirelessLAN imports for the scope-sync handler feature replaced
  with PostgreSQL triggers.
- extras test_management_commands.py: unioned ConfigContext + ImageAttachment
  imports.
- Rebuilt project-static dist bundles (netbox.js/.map/.css) from merged source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Jeremy Stretch 5 일 전
부모
커밋
d28f0a2114
100개의 변경된 파일2202개의 추가작업 그리고 4410개의 파일을 삭제
  1. 0 1
      .github/ISSUE_TEMPLATE/01-feature_request.yaml
  2. 0 1
      .github/ISSUE_TEMPLATE/02-bug_report.yaml
  3. 0 1
      .github/ISSUE_TEMPLATE/03-performance.yaml
  4. 1 1
      .github/workflows/ci.yml
  5. 1 1
      .pre-commit-config.yaml
  6. 3 2
      base_requirements.txt
  7. 134 25
      contrib/openapi.json
  8. 102 0
      docs/administration/management-commands.md
  9. 2 2
      docs/customization/custom-scripts.md
  10. 6 4
      docs/development/release-checklist.md
  11. 3 3
      docs/features/configuration-rendering.md
  12. 1 1
      docs/integrations/graphql-api.md
  13. 9 9
      docs/integrations/rest-api.md
  14. 1 1
      docs/reference/filtering.md
  15. 0 87
      docs/release-notes/index.md
  16. 0 232
      docs/release-notes/version-2.0.md
  17. 0 154
      docs/release-notes/version-2.1.md
  18. 0 349
      docs/release-notes/version-2.10.md
  19. 0 443
      docs/release-notes/version-2.11.md
  20. 0 227
      docs/release-notes/version-2.2.md
  21. 0 225
      docs/release-notes/version-2.3.md
  22. 0 234
      docs/release-notes/version-2.4.md
  23. 0 367
      docs/release-notes/version-2.5.md
  24. 0 507
      docs/release-notes/version-2.6.md
  25. 0 573
      docs/release-notes/version-2.7.md
  26. 0 270
      docs/release-notes/version-2.8.md
  27. 0 335
      docs/release-notes/version-2.9.md
  28. 38 0
      docs/release-notes/version-4.6.md
  29. 1 12
      mkdocs.yml
  30. 0 9
      netbox/core/graphql/filter_mixins.py
  31. 22 7
      netbox/dcim/api/serializers_/devices.py
  32. 33 0
      netbox/dcim/cable_profiles.py
  33. 2 0
      netbox/dcim/choices.py
  34. 1 0
      netbox/dcim/models/cables.py
  35. 6 1
      netbox/dcim/models/modules.py
  36. 20 0
      netbox/dcim/signals.py
  37. 1 1
      netbox/dcim/tests/query_counts.json
  38. 122 1
      netbox/dcim/tests/test_api.py
  39. 53 0
      netbox/dcim/tests/test_cable_profiles.py
  40. 48 0
      netbox/dcim/tests/test_forms.py
  41. 39 0
      netbox/dcim/tests/test_models.py
  42. 66 0
      netbox/dcim/tests/test_search.py
  43. 68 3
      netbox/dcim/tests/test_views.py
  44. 2 1
      netbox/extras/api/serializers_/attachments.py
  45. 12 1
      netbox/extras/api/serializers_/scripts.py
  46. 8 0
      netbox/extras/constants.py
  47. 3 1
      netbox/extras/filtersets.py
  48. 11 1
      netbox/extras/graphql/filters.py
  49. 62 0
      netbox/extras/management/commands/populate_image_sizes.py
  50. 16 0
      netbox/extras/migrations/0140_imageattachment_image_size.py
  51. 52 20
      netbox/extras/models/customfields.py
  52. 63 4
      netbox/extras/models/models.py
  53. 1 1
      netbox/extras/tables/tables.py
  54. 2 1
      netbox/extras/templatetags/custom_links.py
  55. 73 3
      netbox/extras/tests/test_api.py
  56. 42 0
      netbox/extras/tests/test_customfields.py
  57. 19 4
      netbox/extras/tests/test_filtersets.py
  58. 64 1
      netbox/extras/tests/test_management_commands.py
  59. 208 0
      netbox/extras/tests/test_models.py
  60. 75 0
      netbox/extras/tests/test_templatetags.py
  61. 45 1
      netbox/extras/tests/test_views.py
  62. 4 4
      netbox/ipam/forms/bulk_import.py
  63. 71 0
      netbox/ipam/tests/test_forms.py
  64. 9 2
      netbox/netbox/api/gfk_fields.py
  65. 3 1
      netbox/netbox/authentication/misc.py
  66. 3 3
      netbox/netbox/middleware.py
  67. 4 4
      netbox/netbox/settings.py
  68. 3 0
      netbox/netbox/tables/columns.py
  69. 32 0
      netbox/netbox/tables/tables.py
  70. 0 0
      netbox/netbox/tests/dummy_plugin/tests/__init__.py
  71. 19 0
      netbox/netbox/tests/dummy_plugin/tests/test_graphql.py
  72. 43 0
      netbox/netbox/tests/test_authentication.py
  73. 5 1
      netbox/netbox/tests/test_graphql.py
  74. 158 0
      netbox/netbox/tests/test_middleware.py
  75. 4 4
      netbox/netbox/tests/test_views.py
  76. 2 2
      netbox/netbox/views/misc.py
  77. 0 1
      netbox/project-static/.prettierrc
  78. 0 0
      netbox/project-static/dist/netbox.css
  79. 0 0
      netbox/project-static/dist/netbox.js
  80. 0 0
      netbox/project-static/dist/netbox.js.map
  81. 5 5
      netbox/project-static/package.json
  82. 1 1
      netbox/project-static/src/forms/savedFiltersSelect.ts
  83. 12 0
      netbox/project-static/src/select/classes/netboxTomSelect.ts
  84. 15 6
      netbox/project-static/styles/transitional/_navigation.scss
  85. 75 75
      netbox/project-static/yarn.lock
  86. 2 2
      netbox/release.yaml
  87. 1 1
      netbox/templates/core/configrevision_restore.html
  88. 1 1
      netbox/templates/dcim/inc/panels/inventory_items.html
  89. 1 1
      netbox/templates/dcim/panels/component_inventory_items.html
  90. 1 1
      netbox/templates/dcim/panels/interface_wireless.html
  91. 1 1
      netbox/templates/dcim/virtualchassis_edit.html
  92. 1 1
      netbox/templates/extras/inc/script_list_content.html
  93. 2 2
      netbox/templates/generic/object_list.html
  94. 11 0
      netbox/templates/htmx/table.html
  95. 7 3
      netbox/templates/inc/table_controls_htmx.html
  96. 1 1
      netbox/templates/ipam/inc/panels/fhrp_groups.html
  97. 1 1
      netbox/templates/ipam/panels/fhrp_groups.html
  98. BIN
      netbox/translations/cs/LC_MESSAGES/django.mo
  99. 163 158
      netbox/translations/cs/LC_MESSAGES/django.po
  100. BIN
      netbox/translations/da/LC_MESSAGES/django.mo

+ 0 - 1
.github/ISSUE_TEMPLATE/01-feature_request.yaml

@@ -15,7 +15,6 @@ body:
     attributes:
       label: NetBox version
       description: What version of NetBox are you currently running?
-      placeholder: v4.6.3
     validations:
       required: true
   - type: dropdown

+ 0 - 1
.github/ISSUE_TEMPLATE/02-bug_report.yaml

@@ -27,7 +27,6 @@ body:
     attributes:
       label: NetBox Version
       description: What version of NetBox are you currently running?
-      placeholder: v4.6.3
     validations:
       required: true
   - type: dropdown

+ 0 - 1
.github/ISSUE_TEMPLATE/03-performance.yaml

@@ -8,7 +8,6 @@ body:
     attributes:
       label: NetBox Version
       description: What version of NetBox are you currently running?
-      placeholder: v4.6.3
     validations:
       required: true
   - type: dropdown

+ 1 - 1
.github/workflows/ci.yml

@@ -70,7 +70,7 @@ jobs:
       - name: Check Python linting & PEP8 compliance
         uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b  # v4.0.0
         with:
-          version: "0.15.10"
+          version: "0.15.20"
           args: "check --output-format=github"
           src: "netbox/"
 

+ 1 - 1
.pre-commit-config.yaml

@@ -1,6 +1,6 @@
 repos:
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.15.2
+  rev: v0.15.20
   hooks:
     - id: ruff
       name: "Ruff linter"

+ 3 - 2
base_requirements.txt

@@ -34,8 +34,9 @@ django-htmx
 django-mptt
 
 # Context managers for PostgreSQL advisory locks
-# https://github.com/Xof/django-pglocks/blob/master/CHANGES.txt
-django-pglocks
+# https://github.com/Xof/django-pglocks/blob/main/CHANGELOG.md
+# django-pglocks has been merged into django-pgware (see #22571)
+django-pglocks==1.0.4
 
 # Prometheus metrics library for Django
 # https://github.com/korfuri/django-prometheus/blob/master/CHANGELOG.md

+ 134 - 25
contrib/openapi.json

@@ -2,7 +2,7 @@
     "openapi": "3.0.3",
     "info": {
         "title": "NetBox REST API",
-        "version": "4.6.3",
+        "version": "4.6.4",
         "license": {
             "name": "Apache v2 License"
         }
@@ -28336,7 +28336,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28356,7 +28356,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28369,7 +28369,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28382,7 +28382,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28395,7 +28395,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28408,7 +28408,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28421,7 +28421,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28434,7 +28434,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28447,7 +28447,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28460,7 +28460,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28473,7 +28473,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -28486,7 +28486,7 @@
                             "type": "array",
                             "items": {
                                 "type": "string",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             }
                         },
                         "explode": true,
@@ -142065,6 +142065,91 @@
                         "explode": true,
                         "style": "form"
                     },
+                    {
+                        "in": "query",
+                        "name": "image_size",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__empty",
+                        "schema": {
+                            "type": "boolean"
+                        }
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__gt",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__gte",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__lt",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__lte",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
+                    {
+                        "in": "query",
+                        "name": "image_size__n",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "type": "integer",
+                                "format": "int32"
+                            }
+                        },
+                        "explode": true,
+                        "style": "form"
+                    },
                     {
                         "in": "query",
                         "name": "image_width",
@@ -239039,6 +239124,12 @@
                         },
                         "readOnly": true
                     },
+                    "dns_name": {
+                        "type": "string",
+                        "description": "Hostname or FQDN (not case-sensitive)",
+                        "pattern": "^([0-9A-Za-z_-]+|\\*)(\\.[0-9A-Za-z_-]+)*\\.?$",
+                        "maxLength": 255
+                    },
                     "description": {
                         "type": "string",
                         "maxLength": 200
@@ -239069,6 +239160,12 @@
                         ],
                         "nullable": true
                     },
+                    "dns_name": {
+                        "type": "string",
+                        "description": "Hostname or FQDN (not case-sensitive)",
+                        "pattern": "^([0-9A-Za-z_-]+|\\*)(\\.[0-9A-Za-z_-]+)*\\.?$",
+                        "maxLength": 255
+                    },
                     "description": {
                         "type": "string",
                         "maxLength": 200
@@ -242685,11 +242782,12 @@
                             "breakout-1c2p-2c1p",
                             "breakout-1c4p-4c1p",
                             "breakout-1c6p-6c1p",
+                            "breakout-1c8p-8c1p",
                             "breakout-2c4p-8c1p-shuffle"
                         ],
                         "type": "string",
-                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                        "x-spec-enum-id": "f566e6df6572f5d0"
+                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                        "x-spec-enum-id": "6a5f5cb8eec72982"
                     },
                     "tenant": {
                         "oneOf": [
@@ -255569,11 +255667,12 @@
                                     "breakout-1c2p-2c1p",
                                     "breakout-1c4p-4c1p",
                                     "breakout-1c6p-6c1p",
+                                    "breakout-1c8p-8c1p",
                                     "breakout-2c4p-8c1p-shuffle"
                                 ],
                                 "type": "string",
-                                "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                                "x-spec-enum-id": "f566e6df6572f5d0"
+                                "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                                "x-spec-enum-id": "6a5f5cb8eec72982"
                             },
                             "label": {
                                 "type": "string",
@@ -255602,6 +255701,7 @@
                                     "1C2P:2C1P breakout",
                                     "1C4P:4C1P breakout",
                                     "1C6P:6C1P breakout",
+                                    "1C8P:8C1P breakout",
                                     "2C4P:8C1P breakout (shuffle)"
                                 ]
                             }
@@ -255942,11 +256042,12 @@
                             "breakout-1c2p-2c1p",
                             "breakout-1c4p-4c1p",
                             "breakout-1c6p-6c1p",
+                            "breakout-1c8p-8c1p",
                             "breakout-2c4p-8c1p-shuffle"
                         ],
                         "type": "string",
-                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                        "x-spec-enum-id": "f566e6df6572f5d0"
+                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                        "x-spec-enum-id": "6a5f5cb8eec72982"
                     },
                     "tenant": {
                         "oneOf": [
@@ -267300,6 +267401,10 @@
                         "type": "integer",
                         "readOnly": true
                     },
+                    "image_size": {
+                        "type": "integer",
+                        "readOnly": true
+                    },
                     "created": {
                         "type": "string",
                         "format": "date-time",
@@ -267319,6 +267424,7 @@
                     "id",
                     "image",
                     "image_height",
+                    "image_size",
                     "image_width",
                     "last_updated",
                     "object_id",
@@ -280060,11 +280166,12 @@
                             "breakout-1c2p-2c1p",
                             "breakout-1c4p-4c1p",
                             "breakout-1c6p-6c1p",
+                            "breakout-1c8p-8c1p",
                             "breakout-2c4p-8c1p-shuffle"
                         ],
                         "type": "string",
-                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                        "x-spec-enum-id": "f566e6df6572f5d0"
+                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                        "x-spec-enum-id": "6a5f5cb8eec72982"
                     },
                     "tenant": {
                         "oneOf": [
@@ -296041,12 +296148,13 @@
                             "breakout-1c2p-2c1p",
                             "breakout-1c4p-4c1p",
                             "breakout-1c6p-6c1p",
+                            "breakout-1c8p-8c1p",
                             "breakout-2c4p-8c1p-shuffle",
                             ""
                         ],
                         "type": "string",
-                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                        "x-spec-enum-id": "f566e6df6572f5d0"
+                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                        "x-spec-enum-id": "6a5f5cb8eec72982"
                     },
                     "tenant": {
                         "oneOf": [
@@ -319149,12 +319257,13 @@
                             "breakout-1c2p-2c1p",
                             "breakout-1c4p-4c1p",
                             "breakout-1c6p-6c1p",
+                            "breakout-1c8p-8c1p",
                             "breakout-2c4p-8c1p-shuffle",
                             ""
                         ],
                         "type": "string",
-                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
-                        "x-spec-enum-id": "f566e6df6572f5d0"
+                        "description": "* `single-1c1p` - 1C1P\n* `single-1c2p` - 1C2P\n* `single-1c4p` - 1C4P\n* `single-1c6p` - 1C6P\n* `single-1c8p` - 1C8P\n* `single-1c12p` - 1C12P\n* `single-1c16p` - 1C16P\n* `trunk-2c1p` - 2C1P trunk\n* `trunk-2c2p` - 2C2P trunk\n* `trunk-2c4p` - 2C4P trunk\n* `trunk-2c4p-shuffle` - 2C4P trunk (shuffle)\n* `trunk-2c6p` - 2C6P trunk\n* `trunk-2c8p` - 2C8P trunk\n* `trunk-2c12p` - 2C12P trunk\n* `trunk-4c1p` - 4C1P trunk\n* `trunk-4c2p` - 4C2P trunk\n* `trunk-4c4p` - 4C4P trunk\n* `trunk-4c4p-shuffle` - 4C4P trunk (shuffle)\n* `trunk-4c6p` - 4C6P trunk\n* `trunk-4c8p` - 4C8P trunk\n* `trunk-8c4p` - 8C4P trunk\n* `breakout-1c2p-2c1p` - 1C2P:2C1P breakout\n* `breakout-1c4p-4c1p` - 1C4P:4C1P breakout\n* `breakout-1c6p-6c1p` - 1C6P:6C1P breakout\n* `breakout-1c8p-8c1p` - 1C8P:8C1P breakout\n* `breakout-2c4p-8c1p-shuffle` - 2C4P:8C1P breakout (shuffle)",
+                        "x-spec-enum-id": "6a5f5cb8eec72982"
                     },
                     "tenant": {
                         "oneOf": [

+ 102 - 0
docs/administration/management-commands.md

@@ -0,0 +1,102 @@
+# Management Commands
+
+In addition to Django's built-in management commands, NetBox provides several commands of its own. These are run using `manage.py`:
+
+```
+cd /opt/netbox
+source /opt/netbox/venv/bin/activate
+python3 netbox/manage.py <command>
+```
+
+Run any command with `--help` to see its full set of arguments.
+
+## calculate_cached_counts
+
+Force a recalculation of all cached counter fields (for example, the device count shown on a site). NetBox keeps these counters current automatically; this command is useful to repair them if they have drifted.
+
+```
+python3 netbox/manage.py calculate_cached_counts
+```
+
+## nbshell
+
+Start the Django shell with all NetBox models already imported. See [NetBox Shell](./netbox-shell.md) for details.
+
+```
+python3 netbox/manage.py nbshell
+```
+
+## populate_image_sizes
+
+!!! info "This command was introduced in NetBox v4.6.4."
+
+Populate the cached file size for image attachments that predate the `image_size` field. Running this once after upgrading is recommended for deployments with many existing attachments on a remote storage backend (such as S3). It is safe to run on a live system and may be re-run; any file that cannot be read is skipped and retried on the next run.
+
+```
+python3 netbox/manage.py populate_image_sizes
+```
+
+## rebuild_prefixes
+
+Rebuild the IPAM prefix hierarchy, recalculating the depth and child counts for all prefixes.
+
+```
+python3 netbox/manage.py rebuild_prefixes
+```
+
+## reindex
+
+Reindex objects for the search backend. Pass one or more apps or models to reindex a subset; with no arguments, all models are reindexed. See [Removing a Plugin](../plugins/removal.md) for a related use.
+
+```
+python3 netbox/manage.py reindex [app_label[.ModelName] ...]
+```
+
+## renaturalize
+
+Recalculate natural ordering values for the affected models. Pass one or more `app_label.ModelName` arguments to limit the scope; with no arguments, all models with natural ordering fields are processed.
+
+```
+python3 netbox/manage.py renaturalize [app_label.ModelName ...]
+```
+
+## runscript
+
+Run a [custom script](../customization/custom-scripts.md) from the command line, outside the web UI or API.
+
+```
+python3 netbox/manage.py runscript <module.ScriptName>
+```
+
+## rqworker
+
+Start a background task worker to process queued jobs (provided by django-rq). At least one worker must be running for background tasks such as report and script execution, webhooks, and synchronization to be processed.
+
+```
+python3 netbox/manage.py rqworker
+```
+
+## syncdatasource
+
+Synchronize a data source from its remote upstream. Pass one or more data source names, or `--all` to synchronize every data source.
+
+```
+python3 netbox/manage.py syncdatasource <name> [<name> ...]
+python3 netbox/manage.py syncdatasource --all
+```
+
+## trace_paths
+
+Generate any missing cable paths among all cable termination objects. This is useful after a bulk import of cabling, or to repair paths that were not generated automatically.
+
+```
+python3 netbox/manage.py trace_paths
+```
+
+## webhook_receiver
+
+Start a simple HTTP listener that prints any requests it receives. This is a debugging aid for testing webhooks: point a webhook at the listener and inspect exactly what NetBox sends. It listens on port 9000 by default; pass `--port` to change it and `--no-headers` to suppress the request headers.
+
+```
+python3 netbox/manage.py webhook_receiver [--port PORT] [--no-headers]
+```

+ 2 - 2
docs/customization/custom-scripts.md

@@ -437,7 +437,7 @@ Script modules can be uploaded to NetBox via the REST API by sending a `multipar
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Accept: application/json; indent=4" \
 -F "file=@/path/to/myscript.py" \
 http://netbox/api/extras/scripts/upload/
@@ -515,7 +515,7 @@ To run a script via the REST API, issue a POST request to the script's endpoint
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox/api/extras/scripts/example.MyReport/ \

+ 6 - 4
docs/development/release-checklist.md

@@ -144,7 +144,6 @@ Then, compile these portable (`.po`) files for use in the application:
 
 * Update the version number and published date in `netbox/release.yaml`. Add or remove the designation (e.g. `beta1`) if applicable.
 * Copy the version number from `release.yaml` to `pyproject.toml` in the project root.
-* Update the example version numbers in the feature request, bug report, and performance templates under `.github/ISSUE_TEMPLATES/`.
 * Add a section for this release at the top of the changelog page for the minor version (e.g. `docs/release-notes/version-4.2.md`) listing all relevant changes made in this release.
 
 !!! tip
@@ -162,6 +161,9 @@ This will automatically update the schema file at `contrib/generated_schema.json
 
 ### Update the OpenAPI Schema
 
+!!! warning "Disable all plugins first"
+    Before generating the OpenAPI schema, disable any installed plugins. This will prevent their schemas from being pulled into the generated snapshot.
+
 Update the static OpenAPI schema definition at `contrib/openapi.json` with the management command below. If the schema file is up-to-date, only the NetBox version will be changed.
 
 ```nohighlight
@@ -172,9 +174,9 @@ Update the static OpenAPI schema definition at `contrib/openapi.json` with the m
 
 Keep development tooling versions consistent across the project. If you upgrade a dev-only dependency, update all places where it’s pinned so local tooling and CI run the same versions.
 
-* Ruff:
-  * `.pre-commit-config.yaml`
-  * `.github/workflows/ci.yml`
+* Ruff
+    * `.pre-commit-config.yaml`
+    * `.github/workflows/ci.yml`
 
 ### Submit a Pull Request
 

+ 3 - 3
docs/features/configuration-rendering.md

@@ -53,7 +53,7 @@ NetBox provides a REST API endpoint specifically for rendering the default confi
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox:8000/api/dcim/devices/123/render-config/ \
@@ -81,7 +81,7 @@ To render a specific config template against a device's context data - rather th
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox:8000/api/dcim/devices/123/render-config/ \
@@ -114,7 +114,7 @@ NetBox config templates can also be rendered without being tied to any specific
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox:8000/api/extras/config-templates/123/render/ \

+ 1 - 1
docs/integrations/graphql-api.md

@@ -7,7 +7,7 @@ NetBox provides a read-only [GraphQL](https://graphql.org/) API to complement it
 GraphQL enables the client to specify an arbitrary nested list of fields to include in the response. All queries are made to the root `/graphql` API endpoint. For example, to return the circuit ID and provider name of each circuit with an active status, you can issue a request such as the following:
 
 ```
-curl -H "Authorization: Token $TOKEN" \
+curl -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json" \
 http://netbox/graphql/ \

+ 9 - 9
docs/integrations/rest-api.md

@@ -179,7 +179,7 @@ Together, these values identify a unique object in NetBox. The assigned object (
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox/api/ipam/ip-addresses/ \
@@ -502,7 +502,7 @@ To create a new object, make a `POST` request to the model's _list_ endpoint wit
 
 ```no-highlight
 curl -s -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/ipam/prefixes/ \
 --data '{"prefix": "192.0.2.0/24", "scope_type": "dcim.site", "scope_id": 6}' | jq '.'
@@ -555,7 +555,7 @@ http://netbox/api/ipam/prefixes/ \
 To create multiple instances of a model using a single request, make a `POST` request to the model's _list_ endpoint with a list of JSON objects representing each instance to be created. If successful, the response will contain a list of the newly created instances. The example below illustrates the creation of three new sites.
 
 ```no-highlight
-curl -X POST -H "Authorization: Token $TOKEN" \
+curl -X POST -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; indent=4" \
 http://netbox/api/dcim/sites/ \
@@ -595,7 +595,7 @@ To modify an object which has already been created, make a `PATCH` request to th
 
 ```no-highlight
 curl -s -X PATCH \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/ipam/prefixes/18691/ \
 --data '{"status": "reserved"}' | jq '.'
@@ -652,7 +652,7 @@ Multiple objects can be updated simultaneously by issuing a `PUT` or `PATCH` req
 
 ```no-highlight
 curl -s -X PATCH \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/dcim/sites/ \
 --data '[{"id": 10, "status": "active"}, {"id": 11, "status": "active"}]'
@@ -714,7 +714,7 @@ To delete an object from NetBox, make a `DELETE` request to the model's _detail_
 
 ```no-highlight
 curl -s -X DELETE \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 http://netbox/api/ipam/prefixes/18691/
 ```
 
@@ -729,7 +729,7 @@ NetBox supports the simultaneous deletion of multiple objects of the same type b
 
 ```no-highlight
 curl -s -X DELETE \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/dcim/sites/ \
 --data '[{"id": 10}, {"id": 11}, {"id": 12}]'
@@ -793,7 +793,7 @@ For example, the following API request will create a new site and record a messa
 
 ```no-highlight
 curl -s -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/dcim/sites/ \
 --data '{
@@ -813,7 +813,7 @@ For example, we can upload an image attachment using the `curl` command shown be
 
 ```no-highlight
 curl -X POST \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Accept: application/json; indent=4" \
 -F "object_type=dcim.site" \
 -F "object_id=2" \

+ 1 - 1
docs/reference/filtering.md

@@ -14,7 +14,7 @@ Some models have fields which are limited to specific choices, such as the `stat
 
 ```no-highlight
 $ curl -s -X OPTIONS \
--H "Authorization: Token $TOKEN" \
+-H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 http://netbox/api/ipam/prefixes/ | jq ".actions.POST.status.choices"
 [

+ 0 - 87
docs/release-notes/index.md

@@ -152,90 +152,3 @@ This page contains a history of all major and minor releases since NetBox v2.0.
 * REST API Token Provisioning ([#5264](https://github.com/netbox-community/netbox/issues/5264))
 * New Housekeeping Command ([#6590](https://github.com/netbox-community/netbox/issues/6590))
 * Custom Queue Support for Plugins ([#6651](https://github.com/netbox-community/netbox/issues/6651))
-
-#### [Version 2.11](./version-2.11.md) (April 2021)
-
-* Journaling Support ([#151](https://github.com/netbox-community/netbox/issues/151))
-* Parent Interface Assignments ([#1519](https://github.com/netbox-community/netbox/issues/1519))
-* Pre- and Post-Change Snapshots in Webhooks ([#3451](https://github.com/netbox-community/netbox/issues/3451))
-* Mark as Connected Without a Cable ([#3648](https://github.com/netbox-community/netbox/issues/3648))
-* Allow Assigning Devices to Locations ([#4971](https://github.com/netbox-community/netbox/issues/4971))
-* Dynamic Object Exports ([#4999](https://github.com/netbox-community/netbox/issues/4999))
-* Variable Scope Support for VLAN Groups ([#5284](https://github.com/netbox-community/netbox/issues/5284))
-* New Site Group Model ([#5892](https://github.com/netbox-community/netbox/issues/5892))
-* Improved Change Logging ([#5913](https://github.com/netbox-community/netbox/issues/5913))
-* Provider Network Modeling ([#5986](https://github.com/netbox-community/netbox/issues/5986))
-
-#### [Version 2.10](./version-2.10.md) (December 2020)
-
-* Route Targets ([#259](https://github.com/netbox-community/netbox/issues/259))
-* REST API Bulk Deletion ([#3436](https://github.com/netbox-community/netbox/issues/3436))
-* REST API Bulk Update ([#4882](https://github.com/netbox-community/netbox/issues/4882))
-* Reimplementation of Custom Fields ([#4878](https://github.com/netbox-community/netbox/issues/4878))
-* Improved Cable Trace Performance ([#4900](https://github.com/netbox-community/netbox/issues/4900))
-
-#### [Version 2.9](./version-2.9.md) (August 2020)
-
-* Object-Based Permissions ([#554](https://github.com/netbox-community/netbox/issues/554))
-* Background Execution of Scripts & Reports ([#2006](https://github.com/netbox-community/netbox/issues/2006))
-* Named Virtual Chassis ([#2018](https://github.com/netbox-community/netbox/issues/2018))
-* Changes to Tag Creation ([#3703](https://github.com/netbox-community/netbox/issues/3703))
-* Dedicated Model for VM Interfaces ([#4721](https://github.com/netbox-community/netbox/issues/4721))
-* REST API Endpoints for Users and Groups ([#4877](https://github.com/netbox-community/netbox/issues/4877))
-
-#### [Version 2.8](./version-2.8.md) (April 2020)
-
-* Remote Authentication Support ([#2328](https://github.com/netbox-community/netbox/issues/2328))
-* Plugins ([#3351](https://github.com/netbox-community/netbox/issues/3351))
-
-#### [Version 2.7](./version-2.7.md) (January 2020)
-
-* Enhanced Device Type Import ([#451](https://github.com/netbox-community/netbox/issues/451))
-* Bulk Import of Device Components ([#822](https://github.com/netbox-community/netbox/issues/822))
-* External File Storage ([#1814](https://github.com/netbox-community/netbox/issues/1814))
-* Rack Elevations Rendered via SVG ([#2248](https://github.com/netbox-community/netbox/issues/2248))
-
-#### [Version 2.6](./version-2.6.md) (June 2019)
-
-* Power Panels and Feeds ([#54](https://github.com/netbox-community/netbox/issues/54))
-* Caching ([#2647](https://github.com/netbox-community/netbox/issues/2647))
-* View Permissions ([#323](https://github.com/netbox-community/netbox/issues/323))
-* Custom Links ([#969](https://github.com/netbox-community/netbox/issues/969))
-* Prometheus Metrics ([#3104](https://github.com/netbox-community/netbox/issues/3104))
-
-#### [Version 2.5](./version-2.5.md) (December 2018)
-
-* Patch Panels and Cables ([#20](https://github.com/netbox-community/netbox/issues/20))
-
-#### [Version 2.4](./version-2.4.md) (August 2018)
-
-* Webhooks ([#81](https://github.com/netbox-community/netbox/issues/81))
-* Tagging ([#132](https://github.com/netbox-community/netbox/issues/132))
-* Contextual Configuration Data ([#1349](https://github.com/netbox-community/netbox/issues/1349))
-* Change Logging ([#1898](https://github.com/netbox-community/netbox/issues/1898))
-
-#### [Version 2.3](./version-2.3.md) (February 2018)
-
-* Virtual Chassis ([#99](https://github.com/netbox-community/netbox/issues/99))
-* Interface VLAN Assignments ([#150](https://github.com/netbox-community/netbox/issues/150))
-* Bulk Object Creation via the API ([#1553](https://github.com/netbox-community/netbox/issues/1553))
-* Automatic Provisioning of Next Available Prefixes ([#1694](https://github.com/netbox-community/netbox/issues/1694))
-* Bulk Renaming of Device/VM Components ([#1781](https://github.com/netbox-community/netbox/issues/1781))
-
-#### [Version 2.2](./version-2.2.md) (October 2017)
-
-* Virtual Machines and Clusters ([#142](https://github.com/netbox-community/netbox/issues/142))
-* Custom Validation Reports ([#1511](https://github.com/netbox-community/netbox/issues/1511))
-
-#### [Version 2.1](./version-2.1.md) (July 2017)
-
-* IP Address Roles ([#819](https://github.com/netbox-community/netbox/issues/819))
-* Automatic Provisioning of Next Available IP ([#1246](https://github.com/netbox-community/netbox/issues/1246))
-* NAPALM Integration ([#1348](https://github.com/netbox-community/netbox/issues/1348))
-
-#### [Version 2.0](./version-2.0.md) (May 2017)
-
-* API 2.0 ([#113](https://github.com/netbox-community/netbox/issues/113))
-* Image Attachments ([#152](https://github.com/netbox-community/netbox/issues/152))
-* Global Search ([#159](https://github.com/netbox-community/netbox/issues/159))
-* Rack Elevations View ([#951](https://github.com/netbox-community/netbox/issues/951))

+ 0 - 232
docs/release-notes/version-2.0.md

@@ -1,232 +0,0 @@
-# NetBox v2.0 Release Notes
-
-## v2.0.10 (2017-07-14)
-
-### Bug Fixes
-
-* [#1312](https://github.com/netbox-community/netbox/issues/1312) - Catch error when attempting to activate a user key with an invalid private key
-* [#1333](https://github.com/netbox-community/netbox/issues/1333) - Corrected label on is_console_server field of DeviceType bulk edit form
-* [#1338](https://github.com/netbox-community/netbox/issues/1338) - Allow importing prefixes with "container" status
-* [#1339](https://github.com/netbox-community/netbox/issues/1339) - Fixed disappearing checkbox column under django-tables2 v1.7+
-* [#1342](https://github.com/netbox-community/netbox/issues/1342) - Allow designation of users and groups when creating/editing a secret role
-
----
-
-## v2.0.9 (2017-07-10)
-
-### Bug Fixes
-
-* [#1319](https://github.com/netbox-community/netbox/issues/1319) - Fixed server error when attempting to create console/power connections
-* [#1325](https://github.com/netbox-community/netbox/issues/1325) - Retain interface attachment when editing a circuit termination
-
----
-
-## v2.0.8 (2017-07-05)
-
-### Enhancements
-
-* [#1298](https://github.com/netbox-community/netbox/issues/1298) - Calculate prefix utilization based on its status (container or non-container)
-* [#1303](https://github.com/netbox-community/netbox/issues/1303) - Highlight installed interface connections in green on device view
-* [#1315](https://github.com/netbox-community/netbox/issues/1315) - Enforce lowercase file extensions for image attachments
-
-### Bug Fixes
-
-* [#1279](https://github.com/netbox-community/netbox/issues/1279) - Fix primary_ip assignment during IP address import
-* [#1281](https://github.com/netbox-community/netbox/issues/1281) - Show LLDP neighbors tab on device view only if necessary conditions are met
-* [#1282](https://github.com/netbox-community/netbox/issues/1282) - Fixed tooltips on "mark connected/planned" toggle buttons for device connections
-* [#1288](https://github.com/netbox-community/netbox/issues/1288) - Corrected permission name for deleting image attachments
-* [#1289](https://github.com/netbox-community/netbox/issues/1289) - Retain inside NAT assignment when editing an IP address
-* [#1297](https://github.com/netbox-community/netbox/issues/1297) - Allow passing custom field choice selection PKs to API as string-quoted integers
-* [#1299](https://github.com/netbox-community/netbox/issues/1299) - Corrected permission name for adding services to devices
-
----
-
-## v2.0.7 (2017-06-15)
-
-### Enhancements
-
-* [#626](https://github.com/netbox-community/netbox/issues/626) - Added bulk disconnect function for console/power/interface connections on device view
-
-### Bug Fixes
-
-* [#1238](https://github.com/netbox-community/netbox/issues/1238) - Fix error when editing an IP with a NAT assignment which has no assigned device
-* [#1263](https://github.com/netbox-community/netbox/issues/1263) - Differentiate add and edit permissions for objects
-* [#1265](https://github.com/netbox-community/netbox/issues/1265) - Fix console/power/interface connection validation when selecting a device via live search
-* [#1266](https://github.com/netbox-community/netbox/issues/1266) - Prevent terminating a circuit to an already-connected interface
-* [#1268](https://github.com/netbox-community/netbox/issues/1268) - Fix CSV import error under Python 3
-* [#1273](https://github.com/netbox-community/netbox/issues/1273) - Corrected status choices in IP address import form
-* [#1274](https://github.com/netbox-community/netbox/issues/1274) - Exclude unterminated circuits from topology maps
-* [#1275](https://github.com/netbox-community/netbox/issues/1275) - Raise validation error on prefix import when multiple VLANs are found
-
----
-
-## v2.0.6 (2017-06-12)
-
-### Enhancements
-
-* [#40](https://github.com/netbox-community/netbox/issues/40) - Added IP utilization graph to prefix list
-* [#704](https://github.com/netbox-community/netbox/issues/704) - Allow filtering VLANs by group when editing prefixes
-* [#913](https://github.com/netbox-community/netbox/issues/913) - Added headers to object CSV exports
-* [#990](https://github.com/netbox-community/netbox/issues/990) - Enable logging configuration in configuration.py
-* [#1180](https://github.com/netbox-community/netbox/issues/1180) - Simplified the process of finding related devices when viewing a device
-
-### Bug Fixes
-
-* [#1253](https://github.com/netbox-community/netbox/issues/1253) - Improved `upgrade.sh` to allow forcing Python2
-
----
-
-## v2.0.5 (2017-06-08)
-
-### Notes
-
-The maximum number of objects an API consumer can request has been set to 1000 (e.g. `?limit=1000`). This limit can be modified by defining `MAX_PAGE_SIZE` in confgiuration.py. (To remove this limit, set `MAX_PAGE_SIZE=0`.)
-
-### Enhancements
-
-* [#655](https://github.com/netbox-community/netbox/issues/655) - Implemented header-based CSV import of objects
-* [#1190](https://github.com/netbox-community/netbox/issues/1190) - Allow partial string matching when searching on custom fields
-* [#1237](https://github.com/netbox-community/netbox/issues/1237) - Enabled setting limit=0 to disable pagination in API requests; added `MAX_PAGE_SIZE` configuration setting
-
-### Bug Fixes
-
-* [#837](https://github.com/netbox-community/netbox/issues/837) - Enforce uniqueness where applicable during bulk import of IP addresses
-* [#1226](https://github.com/netbox-community/netbox/issues/1226) - Improved validation for custom field values submitted via the API
-* [#1232](https://github.com/netbox-community/netbox/issues/1232) - Improved rack space validation on bulk import of devices (see #655)
-* [#1235](https://github.com/netbox-community/netbox/issues/1235) - Fix permission name for adding/editing inventory items
-* [#1236](https://github.com/netbox-community/netbox/issues/1236) - Truncate rack names in elevations list; add facility ID
-* [#1239](https://github.com/netbox-community/netbox/issues/1239) - Fix server error when creating VLANGroup via API
-* [#1243](https://github.com/netbox-community/netbox/issues/1243) - Catch ValueError in IP-based object filters
-* [#1244](https://github.com/netbox-community/netbox/issues/1244) - Corrected "device" secrets filter to accept a device name
-
----
-
-## v2.0.4 (2017-05-25)
-
-### Bug Fixes
-
-* [#1206](https://github.com/netbox-community/netbox/issues/1206) - Fix redirection in admin UI after activating secret keys when BASE_PATH is set
-* [#1207](https://github.com/netbox-community/netbox/issues/1207) - Include nested LAG serializer when showing interface connections (API)
-* [#1210](https://github.com/netbox-community/netbox/issues/1210) - Fix TemplateDoesNotExist errors on browsable API views
-* [#1212](https://github.com/netbox-community/netbox/issues/1212) - Allow assigning new VLANs to global VLAN groups
-* [#1213](https://github.com/netbox-community/netbox/issues/1213) - Corrected table header ordering links on object list views
-* [#1214](https://github.com/netbox-community/netbox/issues/1214) - Add status to list of required fields on child device import form
-* [#1219](https://github.com/netbox-community/netbox/issues/1219) - Fix image attachment URLs when BASE_PATH is set
-* [#1220](https://github.com/netbox-community/netbox/issues/1220) - Suppressed innocuous warning about untracked migrations under Python 3
-* [#1229](https://github.com/netbox-community/netbox/issues/1229) - Fix validation error on forms where API search is used
-
----
-
-## v2.0.3 (2017-05-18)
-
-### Enhancements
-
-* [#1196](https://github.com/netbox-community/netbox/issues/1196) - Added a lag_id filter to the API interfaces view
-* [#1198](https://github.com/netbox-community/netbox/issues/1198) - Allow filtering unracked devices on device list
-
-### Bug Fixes
-
-* [#1157](https://github.com/netbox-community/netbox/issues/1157) - Hide nav menu search bar on small displays
-* [#1186](https://github.com/netbox-community/netbox/issues/1186) - Corrected VLAN edit form so that site assignment is not required
-* [#1187](https://github.com/netbox-community/netbox/issues/1187) - Fixed table pagination by introducing a custom table template
-* [#1188](https://github.com/netbox-community/netbox/issues/1188) - Serialize interface LAG as nested objected (API)
-* [#1189](https://github.com/netbox-community/netbox/issues/1189) - Enforce consistent ordering of objects returned by a global search
-* [#1191](https://github.com/netbox-community/netbox/issues/1191) - Bulk selection of IPs under a prefix incorrect when "select all" is used
-* [#1195](https://github.com/netbox-community/netbox/issues/1195) - Unable to create an interface connection when searching for peer device
-* [#1197](https://github.com/netbox-community/netbox/issues/1197) - Fixed status assignment during bulk import of devices, prefixes, IPs, and VLANs
-* [#1199](https://github.com/netbox-community/netbox/issues/1199) - Bulk import of secrets does not prompt user to generate a session key
-* [#1200](https://github.com/netbox-community/netbox/issues/1200) - Form validation error when connecting power ports to power outlets
-
----
-
-## v2.0.2 (2017-05-15)
-
-### Enhancements
-
-* [#1122](https://github.com/netbox-community/netbox/issues/1122) - Include NAT inside IPs in IP address list
-* [#1137](https://github.com/netbox-community/netbox/issues/1137) - Allow filtering devices list by rack
-* [#1170](https://github.com/netbox-community/netbox/issues/1170) - Include A and Z sites for circuits in global search results
-* [#1172](https://github.com/netbox-community/netbox/issues/1172) - Linkify racks in side-by-side elevations view
-* [#1177](https://github.com/netbox-community/netbox/issues/1177) - Render planned connections as dashed lines on topology maps
-* [#1179](https://github.com/netbox-community/netbox/issues/1179) - Adjust topology map text color based on node background
-* On all object edit forms, allow filtering the tenant list by tenant group
-
-### Bug Fixes
-
-* [#1158](https://github.com/netbox-community/netbox/issues/1158) - Exception thrown when creating a device component with an invalid name
-* [#1159](https://github.com/netbox-community/netbox/issues/1159) - Only superusers can see "edit IP" buttons on the device interfaces list
-* [#1160](https://github.com/netbox-community/netbox/issues/1160) - Linkify secrets and tenants in global search results
-* [#1161](https://github.com/netbox-community/netbox/issues/1161) - Fix "add another" behavior when creating an API token
-* [#1166](https://github.com/netbox-community/netbox/issues/1166) - Fixed bulk IP address creation when assigning tenants
-* [#1168](https://github.com/netbox-community/netbox/issues/1168) - Total count of objects missing from list view paginator
-* [#1171](https://github.com/netbox-community/netbox/issues/1171) - Allow removing site assignment when bulk editing VLANs
-* [#1173](https://github.com/netbox-community/netbox/issues/1173) - Tweak interface manager to fall back to naive ordering
-
----
-
-## v2.0.1 (2017-05-10)
-
-### Bug Fixes
-
-* [#1149](https://github.com/netbox-community/netbox/issues/1149) - Port list does not populate when creating a console or power connection
-* [#1150](https://github.com/netbox-community/netbox/issues/1150) - Error when uploading image attachments with Unicode names under Python 2
-* [#1151](https://github.com/netbox-community/netbox/issues/1151) - Server error: name 'escape' is not defined
-* [#1152](https://github.com/netbox-community/netbox/issues/1152) - Unable to edit user keys
-* [#1153](https://github.com/netbox-community/netbox/issues/1153) - UnicodeEncodeError when searching for non-ASCII characters on Python 2
-
----
-
-## v2.0.0 (2017-05-09)
-
-### New Features
-
-#### API 2.0 ([#113](https://github.com/netbox-community/netbox/issues/113))
-
-The NetBox API has been completely rewritten and now features full read/write ability.
-
-#### Image Attachments ([#152](https://github.com/netbox-community/netbox/issues/152))
-
-Users are now able to attach photos and other images to sites, racks, and devices. (Please ensure that the new `media` directory is writable by the system account NetBox runs as.)
-
-#### Global Search ([#159](https://github.com/netbox-community/netbox/issues/159))
-
-NetBox now supports searching across all primary object types at once.
-
-#### Rack Elevations View ([#951](https://github.com/netbox-community/netbox/issues/951))
-
-A new view has been introduced to display the elevations of multiple racks side-by-side.
-
-### Enhancements
-
-* [#154](https://github.com/netbox-community/netbox/issues/154) - Expanded device status field to include options other than active/offline
-* [#430](https://github.com/netbox-community/netbox/issues/430) - Include circuits when rendering topology maps
-* [#578](https://github.com/netbox-community/netbox/issues/578) - Show topology maps not assigned to a site on the home view
-* [#1100](https://github.com/netbox-community/netbox/issues/1100) - Add a "view all" link to completed bulk import views is_pool for prefixes)
-* [#1110](https://github.com/netbox-community/netbox/issues/1110) - Expand bulk edit forms to include boolean fields (e.g. toggle is_pool for prefixes)
-
-### Bug Fixes
-
-From v1.9.6:
-
-* [#403](https://github.com/netbox-community/netbox/issues/403) - Record console/power/interface connects and disconnects as user actions
-* [#853](https://github.com/netbox-community/netbox/issues/853) -  Added "status" field to device bulk import form
-* [#1101](https://github.com/netbox-community/netbox/issues/1101) - Fix AJAX scripting for device component selection forms
-* [#1103](https://github.com/netbox-community/netbox/issues/1103) - Correct handling of validation errors when creating IP addresses in bulk
-* [#1104](https://github.com/netbox-community/netbox/issues/1104) - Fix VLAN assignment on prefix import
-* [#1115](https://github.com/netbox-community/netbox/issues/1115) - Enabled responsive (side-scrolling) tables for small screens
-* [#1116](https://github.com/netbox-community/netbox/issues/1116) - Correct object links on recursive deletion error
-* [#1125](https://github.com/netbox-community/netbox/issues/1125) - Include MAC addresses on a device's interface list
-* [#1144](https://github.com/netbox-community/netbox/issues/1144) - Allow multiple status selections for Prefix, IP address, and VLAN filters
-
-From beta3:
-
-* [#1113](https://github.com/netbox-community/netbox/issues/1113) - Fixed server error when attempting to delete an image attachment
-* [#1114](https://github.com/netbox-community/netbox/issues/1114) - Suppress OSError when attempting to access a deleted image attachment
-* [#1126](https://github.com/netbox-community/netbox/issues/1126) - Fixed server error when editing a user key via admin UI attachment
-* [#1132](https://github.com/netbox-community/netbox/issues/1132) - Prompt user to unlock session key when importing secrets
-
-### Additional Changes
-
-* The Module DCIM model has been renamed to InventoryItem to better reflect its intended function, and to make room for work on [#824](https://github.com/netbox-community/netbox/issues/824).
-* Redundant portions of the admin UI have been removed ([#973](https://github.com/netbox-community/netbox/issues/973)).
-* The Docker build components have been moved into [their own repository](https://github.com/netbox-community/netbox-docker).

+ 0 - 154
docs/release-notes/version-2.1.md

@@ -1,154 +0,0 @@
-# NetBox v2.1 Release Notes
-
-## v2.1.6 (2017-10-11)
-
-### Enhancements
-
-* [#1548](https://github.com/netbox-community/netbox/issues/1548) - Automatically populate tenant assignment when adding an IP address from the prefix view
-* [#1561](https://github.com/netbox-community/netbox/issues/1561) - Added primary IP to the devices table in global search
-* [#1563](https://github.com/netbox-community/netbox/issues/1563) - Made necessary updates for Django REST Framework v3.7.0
-
----
-
-## v2.1.5 (2017-09-25)
-
-### Enhancements
-
-* [#1484](https://github.com/netbox-community/netbox/issues/1484) - Added individual "add VLAN" buttons on the VLAN groups list
-* [#1485](https://github.com/netbox-community/netbox/issues/1485) - Added `BANNER_LOGIN` configuration setting to display a banner on the login page
-* [#1499](https://github.com/netbox-community/netbox/issues/1499) - Added utilization graph to child prefixes table
-* [#1523](https://github.com/netbox-community/netbox/issues/1523) - Improved the natural ordering of interfaces (thanks to [@tarkatronic](https://github.com/tarkatronic))
-* [#1536](https://github.com/netbox-community/netbox/issues/1536) - Improved formatting of aggregate prefix statistics
-
-### Bug Fixes
-
-* [#1469](https://github.com/netbox-community/netbox/issues/1469) - Allow a NAT IP to be assigned as the primary IP for a device
-* [#1472](https://github.com/netbox-community/netbox/issues/1472) - Prevented truncation when displaying secret strings containing HTML characters
-* [#1486](https://github.com/netbox-community/netbox/issues/1486) - Ignore subinterface IDs when validating LLDP neighbor connections
-* [#1489](https://github.com/netbox-community/netbox/issues/1489) - Corrected server error on validation of empty required custom field
-* [#1507](https://github.com/netbox-community/netbox/issues/1507) - Fixed error when creating the next available IP from a prefix within a VRF
-* [#1520](https://github.com/netbox-community/netbox/issues/1520) - Redirect on GET request to bulk edit/delete views
-* [#1522](https://github.com/netbox-community/netbox/issues/1522) - Removed object create/edit forms from the browsable API
-
----
-
-## v2.1.4 (2017-08-30)
-
-### Enhancements
-
-* [#1326](https://github.com/netbox-community/netbox/issues/1326) - Added dropdown widget with common values for circuit speed fields
-* [#1341](https://github.com/netbox-community/netbox/issues/1341) - Added a `MEDIA_ROOT` configuration setting to specify where uploaded files are stored on disk
-* [#1376](https://github.com/netbox-community/netbox/issues/1376) - Ignore anycast addresses when detecting duplicate IPs
-* [#1402](https://github.com/netbox-community/netbox/issues/1402) - Increased max length of name field for device components
-* [#1431](https://github.com/netbox-community/netbox/issues/1431) - Added interface form factor for 10GBASE-CX4
-* [#1432](https://github.com/netbox-community/netbox/issues/1432) - Added a `commit_rate` field to the circuits list search form
-* [#1460](https://github.com/netbox-community/netbox/issues/1460) - Hostnames with no domain are now acceptable in custom URL fields
-
-### Bug Fixes
-
-* [#1429](https://github.com/netbox-community/netbox/issues/1429) - Fixed uptime formatting on device status page
-* [#1433](https://github.com/netbox-community/netbox/issues/1433) - Fixed `devicetype_id` filter for DeviceType components
-* [#1443](https://github.com/netbox-community/netbox/issues/1443) - Fixed API validation error involving custom field data
-* [#1458](https://github.com/netbox-community/netbox/issues/1458) - Corrected permission name on prefix/VLAN roles list
-
----
-
-## v2.1.3 (2017-08-15)
-
-### Bug Fixes
-
-* [#1330](https://github.com/netbox-community/netbox/issues/1330) - Raise validation error when assigning an unrelated IP as the primary IP for a device
-* [#1389](https://github.com/netbox-community/netbox/issues/1389) - Avoid splitting carat/prefix on prefix list
-* [#1400](https://github.com/netbox-community/netbox/issues/1400) - Removed redundant display of assigned device interface from IP address list
-* [#1414](https://github.com/netbox-community/netbox/issues/1414) - Selecting a site from the rack filters automatically updates the available rack groups
-* [#1419](https://github.com/netbox-community/netbox/issues/1419) - Allow editing image attachments without re-uploading an image
-* [#1420](https://github.com/netbox-community/netbox/issues/1420) - Exclude virtual interfaces from device LLDP neighbors view
-* [#1421](https://github.com/netbox-community/netbox/issues/1421) - Improved model validation logic for API serializers
-* Fixed page title capitalization in the browsable API
-
----
-
-## v2.1.2 (2017-08-04)
-
-### Enhancements
-
-* [#992](https://github.com/netbox-community/netbox/issues/992) - Allow the creation of multiple services per device with the same protocol and port
-* Tweaked navigation menu styling
-
-### Bug Fixes
-
-* [#1388](https://github.com/netbox-community/netbox/issues/1388) - Fixed server error when searching globally for IPs/prefixes (rolled back #1379)
-* [#1390](https://github.com/netbox-community/netbox/issues/1390) - Fixed IndexError when viewing available IPs within large IPv6 prefixes
-
----
-
-## v2.1.1 (2017-08-02)
-
-### Enhancements
-
-* [#893](https://github.com/netbox-community/netbox/issues/893) - Allow filtering by null values for NullCharacterFields (e.g. return only unnamed devices)
-* [#1368](https://github.com/netbox-community/netbox/issues/1368) - Render reservations in rack elevations view
-* [#1374](https://github.com/netbox-community/netbox/issues/1374) - Added NAPALM_ARGS and NAPALM_TIMEOUT configiuration parameters
-* [#1375](https://github.com/netbox-community/netbox/issues/1375) - Renamed `NETBOX_USERNAME` and `NETBOX_PASSWORD` configuration parameters to `NAPALM_USERNAME` and `NAPALM_PASSWORD`
-* [#1379](https://github.com/netbox-community/netbox/issues/1379) - Allow searching devices by interface MAC address in global search
-
-### Bug Fixes
-
-* [#461](https://github.com/netbox-community/netbox/issues/461) - Display a validation error when attempting to assigning a new child device to a rack face/position
-* [#1385](https://github.com/netbox-community/netbox/issues/1385) - Connected device API endpoint no longer requires authentication if `LOGIN_REQUIRED` is False
-
----
-
-## v2.1.0 (2017-07-25)
-
-### New Features
-
-#### IP Address Roles ([#819](https://github.com/netbox-community/netbox/issues/819))
-
-The IP address model now supports the assignment of a functional role to help identify special-purpose IPs. These include:
-
-* Loopback
-* Secondary
-* Anycast
-* VIP
-* VRRP
-* HSRP
-* GLBP
-
-#### Automatic Provisioning of Next Available IP ([#1246](https://github.com/netbox-community/netbox/issues/1246))
-
-A new API endpoint has been added at `/api/ipam/prefixes/<pk>/available-ips/`. A GET request to this endpoint will return a list of available IP addresses within the prefix (up to the pagination limit). A POST request will automatically create and return the next available IP address.
-
-#### NAPALM Integration ([#1348](https://github.com/netbox-community/netbox/issues/1348))
-
-The [NAPALM automation](https://github.com/napalm-automation/napalm) library provides an abstracted interface for pulling live data (e.g. uptime, software version, running config, LLDP neighbors, etc.) from network devices. The NetBox API has been extended to support executing read-only NAPALM methods on devices defined in NetBox. To enable this functionality, ensure that NAPALM has been installed (`pip install napalm`) and the `NETBOX_USERNAME` and `NETBOX_PASSWORD` [configuration parameters](https://docs.netbox.dev/en/stable/configuration/optional-settings/#netbox_username) have been set in configuration.py.
-
-### Enhancements
-
-* [#838](https://github.com/netbox-community/netbox/issues/838) - Display details of all objects being edited/deleted in bulk
-* [#1041](https://github.com/netbox-community/netbox/issues/1041) - Added enabled and MTU fields to the interface model
-* [#1121](https://github.com/netbox-community/netbox/issues/1121) - Added asset_tag and description fields to the InventoryItem model
-* [#1141](https://github.com/netbox-community/netbox/issues/1141) - Include RD when listing VRFs in a form selection field
-* [#1203](https://github.com/netbox-community/netbox/issues/1203) - Implemented query filters for all models
-* [#1218](https://github.com/netbox-community/netbox/issues/1218) - Added IEEE 802.11 wireless interface types
-* [#1269](https://github.com/netbox-community/netbox/issues/1269) - Added circuit termination to interface serializer
-* [#1320](https://github.com/netbox-community/netbox/issues/1320) - Removed checkbox from confirmation dialog
-
-### Bug Fixes
-
-* [#1079](https://github.com/netbox-community/netbox/issues/1079) - Order interfaces naturally via API
-* [#1285](https://github.com/netbox-community/netbox/issues/1285) - Enforce model validation when creating/editing objects via the API
-* [#1358](https://github.com/netbox-community/netbox/issues/1358) - Correct VRF example values in IP/prefix import forms
-* [#1362](https://github.com/netbox-community/netbox/issues/1362) - Raise validation error when attempting to create an API key that's too short
-* [#1371](https://github.com/netbox-community/netbox/issues/1371) - Extend DeviceSerializer.parent_device to include standard fields
-
-### API changes
-
-* Added a new API endpoint which makes [NAPALM](https://github.com/napalm-automation/napalm) accessible via NetBox
-* Device components (console ports, power ports, interfaces, etc.) can only be filtered by a single device name or ID. This limitation was necessary to allow the natural ordering of interfaces according to the device's parent device type.
-* Added two new fields to the interface serializer: `enabled` (boolean) and `mtu` (unsigned integer)
-* Modified the interface serializer to include three discrete fields relating to connections: `is_connected` (boolean), `interface_connection`, and `circuit_termination`
-* Added two new fields to the inventory item serializer: `asset_tag` and `description`
-* Added "wireless" to interface type filter (in addition to physical, virtual, and LAG)
-* Added a new endpoint at /api/ipam/prefixes/<pk\>/available-ips/ to retrieve or create available IPs within a prefix
-* Extended `parent_device` on DeviceSerializer to include the `url` and `display_name` of the parent Device, and the `url` of the DeviceBay

+ 0 - 349
docs/release-notes/version-2.10.md

@@ -1,349 +0,0 @@
-# NetBox v2.10
-
-## v2.10.10 (2021-04-15)
-
-### Enhancements
-
-* [#5796](https://github.com/netbox-community/netbox/issues/5796) - Add DC terminal power port, outlet types
-* [#5980](https://github.com/netbox-community/netbox/issues/5980) - Add Saf-D-Grid power port, outlet types
-* [#6157](https://github.com/netbox-community/netbox/issues/6157) - Support Markdown rendering for report logs
-* [#6160](https://github.com/netbox-community/netbox/issues/6160) - Add F connector port type
-* [#6168](https://github.com/netbox-community/netbox/issues/6168) - Add SFP56 50GE interface type
-
-### Bug Fixes
-
-* [#5419](https://github.com/netbox-community/netbox/issues/5419) - Update parent device/VM when deleting a primary IP
-* [#5643](https://github.com/netbox-community/netbox/issues/5643) - Fix VLAN assignment when editing VM interfaces in bulk
-* [#5652](https://github.com/netbox-community/netbox/issues/5652) - Update object data when renaming a custom field
-* [#6056](https://github.com/netbox-community/netbox/issues/6056) - Optimize change log cleanup
-* [#6144](https://github.com/netbox-community/netbox/issues/6144) - Fix MAC address field display in VM interfaces search form
-* [#6152](https://github.com/netbox-community/netbox/issues/6152) - Fix custom field filtering for cables, virtual chassis
-* [#6162](https://github.com/netbox-community/netbox/issues/6162) - Fix choice field filters (multiple models)
-
----
-
-## v2.10.9 (2021-04-12)
-
-### Enhancements
-
-* [#5526](https://github.com/netbox-community/netbox/issues/5526) - Add MAC address search field to VM interfaces list
-* [#5756](https://github.com/netbox-community/netbox/issues/5756) - Omit child devices from non-racked devices list under rack view
-* [#5840](https://github.com/netbox-community/netbox/issues/5840) - Add column to cable termination objects to display cable color
-* [#6054](https://github.com/netbox-community/netbox/issues/6054) - Display NAPALM-enabled device tabs only when relevant
-* [#6083](https://github.com/netbox-community/netbox/issues/6083) - Support disabling TLS certificate validation for Redis
-
-### Bug Fixes
-
-* [#5805](https://github.com/netbox-community/netbox/issues/5805) - Fix missing custom field filters for cables, rack reservations
-* [#6070](https://github.com/netbox-community/netbox/issues/6070) - Add missing `count_ipaddresses` attribute to VMInterface serializer
-* [#6073](https://github.com/netbox-community/netbox/issues/6073) - Permit users to manage their own REST API tokens without needing explicit permission
-* [#6081](https://github.com/netbox-community/netbox/issues/6081) - Fix interface connections REST API endpoint
-* [#6082](https://github.com/netbox-community/netbox/issues/6082) - Support colons in webhook header values
-* [#6108](https://github.com/netbox-community/netbox/issues/6108) - Do not infer tenant assignment from parent objects for prefixes, IP addresses
-* [#6117](https://github.com/netbox-community/netbox/issues/6117) - Handle exception when attempting to assign an MPTT-enabled model as its own parent
-* [#6131](https://github.com/netbox-community/netbox/issues/6131) - Correct handling of boolean fields when cloning objects
-
----
-
-## v2.10.8 (2021-03-26)
-
-### Bug Fixes
-
-* [#6060](https://github.com/netbox-community/netbox/issues/6060) - Fix exception on cable trace in UI (regression from #5650)
-
----
-
-## v2.10.7 (2021-03-25)
-
-### Enhancements
-
-* [#5641](https://github.com/netbox-community/netbox/issues/5641) - Allow filtering device components by label
-* [#5723](https://github.com/netbox-community/netbox/issues/5723) - Allow customization of the geographic mapping service via `MAPS_URL` config parameter
-* [#5736](https://github.com/netbox-community/netbox/issues/5736) - Allow changing site assignment when bulk editing devices
-* [#5953](https://github.com/netbox-community/netbox/issues/5953) - Support Markdown rendering for custom script descriptions
-* [#6040](https://github.com/netbox-community/netbox/issues/6040) - Add UI search fields for asset tag for devices and racks
-
-### Bug Fixes
-
-* [#5595](https://github.com/netbox-community/netbox/issues/5595) - Restore ability to delete an uploaded device type image
-* [#5650](https://github.com/netbox-community/netbox/issues/5650) - Denote when the total length of a cable trace may exceed the indicated value
-* [#5962](https://github.com/netbox-community/netbox/issues/5962) - Ensure consistent display of change log action labels
-* [#5966](https://github.com/netbox-community/netbox/issues/5966) - Skip Markdown reference link when tabbing through form fields
-* [#5977](https://github.com/netbox-community/netbox/issues/5977) - Correct validation of `RELEASE_CHECK_URL` config parameter
-* [#6006](https://github.com/netbox-community/netbox/issues/6006) - Fix VLAN group/site association for bulk prefix import
-* [#6010](https://github.com/netbox-community/netbox/issues/6010) - Eliminate duplicate virtual chassis search results
-* [#6012](https://github.com/netbox-community/netbox/issues/6012) - Pre-populate attributes when creating an available child prefix via the UI
-* [#6023](https://github.com/netbox-community/netbox/issues/6023) - Fix display of bottom banner with uBlock Origin enabled
-
----
-
-## v2.10.6 (2021-03-09)
-
-### Enhancements
-
-* [#5592](https://github.com/netbox-community/netbox/issues/5592) - Add IP addresses count to VRF view
-* [#5630](https://github.com/netbox-community/netbox/issues/5630) - Add QSFP+ (64GFC) FibreChannel Interface option
-* [#5884](https://github.com/netbox-community/netbox/issues/5884) - Enable custom links for device components
-* [#5914](https://github.com/netbox-community/netbox/issues/5914) - Add edit/delete buttons for IP addresses on interface view
-* [#5942](https://github.com/netbox-community/netbox/issues/5942) - Add button to add a new IP address on interface view
-
-### Bug Fixes
-
-* [#5703](https://github.com/netbox-community/netbox/issues/5703) - Fix VRF and Tenant field population when adding IP addresses from prefix
-* [#5819](https://github.com/netbox-community/netbox/issues/5819) - Enable ordering of virtual machines by primary IP address
-* [#5872](https://github.com/netbox-community/netbox/issues/5872) - Ordering of devices by primary IP should respect `PREFER_IPV4` configuration parameter
-* [#5922](https://github.com/netbox-community/netbox/issues/5922) - Fix options for filtering object permissions in admin UI
-* [#5935](https://github.com/netbox-community/netbox/issues/5935) - Fix filtering prefixes list by multiple prefix values
-* [#5948](https://github.com/netbox-community/netbox/issues/5948) - Invalidate cached queries when running `renaturalize`
-
----
-
-## v2.10.5 (2021-02-24)
-
-### Bug Fixes
-
-* [#5315](https://github.com/netbox-community/netbox/issues/5315) - Fix site unassignment from VLAN when using "None" option
-* [#5626](https://github.com/netbox-community/netbox/issues/5626) - Fix REST API representation for circuit terminations connected to non-interface endpoints
-* [#5716](https://github.com/netbox-community/netbox/issues/5716) - Fix filtering rack reservations by custom field
-* [#5718](https://github.com/netbox-community/netbox/issues/5718) - Fix bulk editing of services when no port(s) are defined
-* [#5735](https://github.com/netbox-community/netbox/issues/5735) - Ensure consistent treatment of duplicate IP addresses
-* [#5738](https://github.com/netbox-community/netbox/issues/5738) - Fix redirect to device components view after disconnecting a cable
-* [#5753](https://github.com/netbox-community/netbox/issues/5753) - Fix Redis Sentinel password application for caching
-* [#5786](https://github.com/netbox-community/netbox/issues/5786) - Allow setting null tenant group on tenant via REST API
-* [#5841](https://github.com/netbox-community/netbox/issues/5841) - Disallow the creation of available prefixes/IP addresses in violation of assigned permission constraints
-
----
-
-## v2.10.4 (2021-01-26)
-
-### Enhancements
-
-* [#5542](https://github.com/netbox-community/netbox/issues/5542) - Show cable trace lengths in both meters and feet
-* [#5570](https://github.com/netbox-community/netbox/issues/5570) - Add "management only" filter widget for interfaces list
-* [#5586](https://github.com/netbox-community/netbox/issues/5586) - Allow filtering virtual chassis by name and master
-* [#5612](https://github.com/netbox-community/netbox/issues/5612) - Add GG45 and TERA port types, and CAT7a and CAT8 cable types
-* [#5678](https://github.com/netbox-community/netbox/issues/5678) - Show available type choices for all device component import forms
-
-### Bug Fixes
-
-* [#5232](https://github.com/netbox-community/netbox/issues/5232) - Correct swagger definition for ip_prefixes_available-ips_create API
-* [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types
-* [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view
-* [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address
-* [#5603](https://github.com/netbox-community/netbox/issues/5603) - Fix display of white cables in trace view
-* [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name
-* [#5640](https://github.com/netbox-community/netbox/issues/5640) - Fix permissions assessment when adding VM interfaces in bulk
-* [#5648](https://github.com/netbox-community/netbox/issues/5648) - Include VC member interfaces on interfaces tab count when viewing VC master
-* [#5665](https://github.com/netbox-community/netbox/issues/5665) - Validate rack group is assigned to same site when creating a rack
-* [#5683](https://github.com/netbox-community/netbox/issues/5683) - Correct rack elevation displayed when viewing a reservation
-
----
-
-## v2.10.3 (2021-01-05)
-
-### Bug Fixes
-
-* [#5049](https://github.com/netbox-community/netbox/issues/5049) - Add check for LLDP neighbor chassis name to lldp_neighbors
-* [#5301](https://github.com/netbox-community/netbox/issues/5301) - Fix misleading error when racking a device with invalid parameters
-* [#5311](https://github.com/netbox-community/netbox/issues/5311) - Update child objects when a rack group is moved to a new site
-* [#5518](https://github.com/netbox-community/netbox/issues/5518) - Fix persistent vertical scrollbar
-* [#5533](https://github.com/netbox-community/netbox/issues/5533) - Fix bulk editing of objects with required custom fields
-* [#5540](https://github.com/netbox-community/netbox/issues/5540) - Fix exception when viewing a provider with one or more tags assigned
-* [#5543](https://github.com/netbox-community/netbox/issues/5543) - Fix rendering of config contexts with cluster assignment for devices
-* [#5546](https://github.com/netbox-community/netbox/issues/5546) - Add custom field bulk edit support for cables, power panels, rack reservations, and virtual chassis
-* [#5547](https://github.com/netbox-community/netbox/issues/5547) - Add custom field bulk import support for cables, power panels, rack reservations, and virtual chassis
-* [#5551](https://github.com/netbox-community/netbox/issues/5551) - Restore missing import button on services list
-* [#5557](https://github.com/netbox-community/netbox/issues/5557) - Fix VRF route target assignment via REST API
-* [#5558](https://github.com/netbox-community/netbox/issues/5558) - Fix regex validation support for custom URL fields
-* [#5563](https://github.com/netbox-community/netbox/issues/5563) - Fix power feed cable trace link
-* [#5564](https://github.com/netbox-community/netbox/issues/5564) - Raise validation error if a power port template's `allocated_draw` exceeds its `maximum_draw`
-* [#5569](https://github.com/netbox-community/netbox/issues/5569) - Ensure consistent labeling of interface `mgmt_only` field
-* [#5573](https://github.com/netbox-community/netbox/issues/5573) - Report inconsistent values when migrating custom field data
-
----
-
-## v2.10.2 (2020-12-21)
-
-### Enhancements
-
-* [#5489](https://github.com/netbox-community/netbox/issues/5489) - Add filters for type and width to racks list
-* [#5496](https://github.com/netbox-community/netbox/issues/5496) - Add form field to filter rack reservation by user
-
-### Bug Fixes
-
-* [#5254](https://github.com/netbox-community/netbox/issues/5254) - Require plugin authors to set zip_safe=False
-* [#5468](https://github.com/netbox-community/netbox/issues/5468) - Fix unlocking secrets from device/VM view
-* [#5473](https://github.com/netbox-community/netbox/issues/5473) - Fix alignment of rack names in elevations list
-* [#5478](https://github.com/netbox-community/netbox/issues/5478) - Fix display of route target description
-* [#5484](https://github.com/netbox-community/netbox/issues/5484) - Fix "tagged" indication in VLAN members list
-* [#5486](https://github.com/netbox-community/netbox/issues/5486) - Optimize retrieval of config context data for device/VM REST API views
-* [#5487](https://github.com/netbox-community/netbox/issues/5487) - Support filtering rack type/width with multiple values
-* [#5488](https://github.com/netbox-community/netbox/issues/5488) - Fix caching error when viewing cable trace after toggling cable status
-* [#5498](https://github.com/netbox-community/netbox/issues/5498) - Fix filtering rack reservations by username
-* [#5499](https://github.com/netbox-community/netbox/issues/5499) - Fix filtering of displayed device/VM interfaces by regex
-* [#5507](https://github.com/netbox-community/netbox/issues/5507) - Fix custom field data assignment via UI for IP addresses, secrets
-* [#5510](https://github.com/netbox-community/netbox/issues/5510) - Fix filtering by boolean custom fields
-
----
-
-## v2.10.1 (2020-12-15)
-
-### Bug Fixes
-
-* [#5444](https://github.com/netbox-community/netbox/issues/5444) - Don't force overwriting of boolean fields when bulk editing interfaces
-* [#5450](https://github.com/netbox-community/netbox/issues/5450) - API serializer foreign count fields do not have a default value
-* [#5453](https://github.com/netbox-community/netbox/issues/5453) - Correct change log representation when creating a cable
-* [#5458](https://github.com/netbox-community/netbox/issues/5458) - Creating a component template throws an exception
-* [#5461](https://github.com/netbox-community/netbox/issues/5461) - Rack Elevations throw reverse match exception
-* [#5463](https://github.com/netbox-community/netbox/issues/5463) - Back-to-back Circuit Termination throws AttributeError exception
-* [#5465](https://github.com/netbox-community/netbox/issues/5465) - Correct return URL when disconnecting a cable from a device
-* [#5466](https://github.com/netbox-community/netbox/issues/5466) - Fix validation for required custom fields
-* [#5470](https://github.com/netbox-community/netbox/issues/5470) - Fix exception when making `OPTIONS` request for a REST API list endpoint
-
----
-
-## v2.10.0 (2020-12-14)
-
-**NOTE:** This release completely removes support for embedded graphs.
-
-**NOTE:** The Django templating language (DTL) is no longer supported for export templates. Ensure that all export templates use Jinja2 before upgrading.
-
-### New Features
-
-#### Route Targets ([#259](https://github.com/netbox-community/netbox/issues/259))
-
-This release introduces support for modeling L3VPN route targets, which can be used to control the redistribution of advertised prefixes among VRFs. Each VRF may be assigned one or more route targets in the import and/or export direction. Like VRFs, route targets may be assigned to tenants and support tag assignment.
-
-#### REST API Bulk Deletion ([#3436](https://github.com/netbox-community/netbox/issues/3436))
-
-The REST API now supports the bulk deletion of objects of the same type in a single request. Send a `DELETE` HTTP request to the list to the model's list endpoint (e.g. `/api/dcim/sites/`) with a list of JSON objects specifying the numeric ID of each object to be deleted. For example, to delete sites with IDs 10, 11, and 12, issue the following request:
-
-```no-highlight
-curl -s -X DELETE \
--H "Authorization: Token $TOKEN" \
--H "Content-Type: application/json" \
-http://netbox/api/dcim/sites/ \
---data '[{"id": 10}, {"id": 11}, {"id": 12}]'
-```
-
-#### REST API Bulk Update ([#4882](https://github.com/netbox-community/netbox/issues/4882))
-
-Similar to bulk deletion, the REST API also now supports bulk updates. Send a `PUT` or `PATCH` HTTP request to the list to the model's list endpoint (e.g. `/api/dcim/sites/`) with a list of JSON objects specifying the numeric ID of each object and the attribute(s) to be updated. For example, to set a description for sites with IDs 10 and 11, issue the following request:
-
-```no-highlight
-curl -s -X PATCH \
--H "Authorization: Token $TOKEN" \
--H "Content-Type: application/json" \
-http://netbox/api/dcim/sites/ \
---data '[{"id": 10, "description": "Foo"}, {"id": 11, "description": "Bar"}]'
-```
-
-#### Reimplementation of Custom Fields ([#4878](https://github.com/netbox-community/netbox/issues/4878))
-
-NetBox v2.10 introduces a completely overhauled approach to custom fields. Whereas previous versions used CustomFieldValue instances to store values, custom field data is now stored directly on each model instance as JSON data and may be accessed using the `cf` property:
-
-```python
->>> site = Site.objects.first()
->>> site.cf
-{'site_code': 'US-RAL01'}
->>> site.cf['foo'] = 'ABC'
->>> site.full_clean()
->>> site.save()
->>> site = Site.objects.first()
->>> site.cf
-{'foo': 'ABC', 'site_code': 'US-RAL01'}
-```
-
-Additionally, custom selection field choices are now defined on the CustomField model within the admin UI, which greatly simplifies working with choice values.
-
-#### Improved Cable Trace Performance ([#4900](https://github.com/netbox-community/netbox/issues/4900))
-
-All end-to-end cable paths are now cached using the new CablePath backend model. This allows NetBox to now immediately return the complete path originating from any endpoint directly from the database, rather than having to trace each cable recursively. It also resolves some systemic validation issues present in the original implementation.
-
-**Note:** As part of this change, cable traces will no longer traverse circuits: A circuit termination will be considered the origin or destination of an end-to-end path.
-
-### Enhancements
-
-* [#609](https://github.com/netbox-community/netbox/issues/609) - Add min/max value and regex validation for custom fields
-* [#1503](https://github.com/netbox-community/netbox/issues/1503) - Allow assigment of secrets to virtual machines
-* [#1692](https://github.com/netbox-community/netbox/issues/1692) - Allow assigment of inventory items to parent items in web UI
-* [#2179](https://github.com/netbox-community/netbox/issues/2179) - Support the use of multiple port numbers when defining a service
-* [#4897](https://github.com/netbox-community/netbox/issues/4897) - Allow filtering by content type identified as `<app>.<model>` string
-* [#4918](https://github.com/netbox-community/netbox/issues/4918) - Add a REST API endpoint (`/api/status/`) which returns NetBox's current operational status
-* [#4956](https://github.com/netbox-community/netbox/issues/4956) - Include inventory items on primary device view
-* [#4967](https://github.com/netbox-community/netbox/issues/4967) - Support tenant assignment for aggregates
-* [#5003](https://github.com/netbox-community/netbox/issues/5003) - CSV import now accepts slug values for choice fields
-* [#5146](https://github.com/netbox-community/netbox/issues/5146) - Add custom field support for cables, power panels, rack reservations, and virtual chassis
-* [#5154](https://github.com/netbox-community/netbox/issues/5154) - The web interface now consumes the entire browser window
-* [#5190](https://github.com/netbox-community/netbox/issues/5190) - Add a REST API endpoint for retrieving content types (`/api/extras/content-types/`)
-* [#5274](https://github.com/netbox-community/netbox/issues/5274) - Add REST API support for custom fields
-* [#5399](https://github.com/netbox-community/netbox/issues/5399) - Show options for cable endpoint types during bulk import
-* [#5411](https://github.com/netbox-community/netbox/issues/5411) - Include cable tags in trace view
-
-### Other Changes
-
-* [#1846](https://github.com/netbox-community/netbox/issues/1846) - Enable MPTT for InventoryItem hierarchy
-* [#2755](https://github.com/netbox-community/netbox/issues/2755) - Switched from Font Awesome/Glyphicons to Material Design icons
-* [#4349](https://github.com/netbox-community/netbox/issues/4349) - Dropped support for embedded graphs
-* [#4360](https://github.com/netbox-community/netbox/issues/4360) - Dropped support for the Django template language from export templates
-* [#4711](https://github.com/netbox-community/netbox/issues/4711) - Renamed Webhook `obj_type` to `content_types`
-* [#4941](https://github.com/netbox-community/netbox/issues/4941) - `commit` argument is now required argument in a custom script's `run()` method
-* [#5011](https://github.com/netbox-community/netbox/issues/5011) - Standardized name field lengths across all models
-* [#5139](https://github.com/netbox-community/netbox/issues/5139) - Omit utilization statistics from RIR list
-* [#5225](https://github.com/netbox-community/netbox/issues/5225) - Circuit termination port speed is now an optional field
-
-### REST API Changes
-
-* Added support for `PUT`, `PATCH`, and `DELETE` operations on list endpoints (bulk update and delete)
-* Added the `/extras/content-types/` endpoint for Django ContentTypes
-* Added the `/extras/custom-fields/` endpoint for custom fields
-* Removed the `/extras/_custom_field_choices/` endpoint (replaced by new custom fields endpoint)
-* Added the `/status/` endpoint to convey NetBox's current status
-* circuits.CircuitTermination:
-    * Added the `/trace/` endpoint
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * `port_speed` may now be null
-* dcim.Cable: Added `custom_fields`
-* dcim.ConsolePort:
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * Removed `connection_status` from nested serializer
-* dcim.ConsoleServerPort:
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * Removed `connection_status` from nested serializer
-* dcim.FrontPort:
-    * Replaced the `/trace/` endpoint with `/paths/`, which returns a list of cable paths
-    * Added `cable_peer` and `cable_peer_type`
-* dcim.Interface:
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * Removed `connection_status` from nested serializer
-* dcim.InventoryItem: The `_depth` field has been added to reflect MPTT positioning
-* dcim.PowerFeed:
-    * Added the `/trace/` endpoint
-    * Added fields `connected_endpoint`, `connected_endpoint_type`, `connected_endpoint_reachable`, `cable_peer`, and `cable_peer_type`
-* dcim.PowerOutlet:
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * Removed `connection_status` from nested serializer
-* dcim.PowerPanel: Added `custom_fields`
-* dcim.PowerPort
-    * Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
-    * Added `cable_peer` and `cable_peer_type`
-    * Removed `connection_status` from nested serializer
-* dcim.RackReservation: Added `custom_fields`
-* dcim.RearPort:
-    * Replaced the `/trace/` endpoint with `/paths/`, which returns a list of cable paths
-    * Added `cable_peer` and `cable_peer_type`
-* dcim.VirtualChassis: Added `custom_fields`
-* extras.ExportTemplate: The `template_language` field has been removed
-* extras.Graph: This API endpoint has been removed (see #4349)
-* extras.ImageAttachment: Filtering by `content_type` now takes a string in the form `<app>.<model>`
-* extras.ObjectChange: Filtering by `changed_object_type` now takes a string in the form `<app>.<model>`
-* ipam.Aggregate: Added `tenant` field
-* ipam.RouteTarget: New endpoint
-* ipam.Service: Renamed `port` to `ports`; now holds a list of one or more port numbers
-* ipam.VRF: Added `import_targets` and `export_targets` fields
-* secrets.Secret: Removed `device` field; replaced with `assigned_object` generic foreign key. This may represent either a device or a virtual machine. Assign an object by setting `assigned_object_type` and `assigned_object_id`.

+ 0 - 443
docs/release-notes/version-2.11.md

@@ -1,443 +0,0 @@
-# NetBox v2.11
-
-## v2.11.12 (2021-08-23)
-
-### Enhancements
-
-* [#6748](https://github.com/netbox-community/netbox/issues/6748) - Add site group filter to devices list
-* [#6790](https://github.com/netbox-community/netbox/issues/6790) - Recognize a /32 IPv4 address as a child of a /32 IPv4 prefix
-* [#6872](https://github.com/netbox-community/netbox/issues/6872) - Add table configuration button to child prefixes view
-* [#6929](https://github.com/netbox-community/netbox/issues/6929) - Introduce `LOGIN_PERSISTENCE` configuration parameter to persist user sessions
-* [#7011](https://github.com/netbox-community/netbox/issues/7011) - Add search field to VM interfaces filter form
-
-### Bug Fixes
-
-* [#5968](https://github.com/netbox-community/netbox/issues/5968) - Model forms should save empty custom field values as null
-* [#6326](https://github.com/netbox-community/netbox/issues/6326) - Enable filtering assigned VLANs by group in interface edit form
-* [#6686](https://github.com/netbox-community/netbox/issues/6686) - Force assignment of null custom field values to objects
-* [#6776](https://github.com/netbox-community/netbox/issues/6776) - Fix erroneous webhook dispatch on failure to save objects
-* [#6974](https://github.com/netbox-community/netbox/issues/6974) - Show contextual label for IP address role
-* [#7012](https://github.com/netbox-community/netbox/issues/7012) - Fix hidden "add components" dropdown on devices list
-
----
-
-## v2.11.11 (2021-08-12)
-
-### Enhancements
-
-* [#6883](https://github.com/netbox-community/netbox/issues/6883) - Add C21 & C22 power types
-* [#6921](https://github.com/netbox-community/netbox/issues/6921) - Employ a sandbox when rendering Jinja2 code for increased security
-
-### Bug Fixes
-
-* [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list
-* [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation
-* [#6896](https://github.com/netbox-community/netbox/issues/6896) - Fix validation of IP address assigned as device/VM primary via NAT relation
-* [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components
-* [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import
-* [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form
-* [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name
-* [#6918](https://github.com/netbox-community/netbox/issues/6918) - Fix return URL persistence when adding multiple objects sequentially
-* [#6935](https://github.com/netbox-community/netbox/issues/6935) - Remove extraneous columns from inventory item and device bay tables
-* [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form
-
----
-
-## v2.11.10 (2021-07-28)
-
-### Enhancements
-
-* [#6560](https://github.com/netbox-community/netbox/issues/6560) - Enable CSV import via uploaded file
-* [#6644](https://github.com/netbox-community/netbox/issues/6644) - Add 6P/4P pass-through port types
-* [#6771](https://github.com/netbox-community/netbox/issues/6771) - Add count of inventory items to manufacturer view
-* [#6785](https://github.com/netbox-community/netbox/issues/6785) - Add "hardwired" type for power port types
-
-### Bug Fixes
-
-* [#5442](https://github.com/netbox-community/netbox/issues/5442) - Fix assignment of permissions based on LDAP groups
-* [#5627](https://github.com/netbox-community/netbox/issues/5627) - Fix filtering of interface connections list
-* [#6759](https://github.com/netbox-community/netbox/issues/6759) - Fix assignment of parent interfaces for bulk import
-* [#6773](https://github.com/netbox-community/netbox/issues/6773) - Add missing `display` field to rack unit serializer
-* [#6774](https://github.com/netbox-community/netbox/issues/6774) - Fix A/Z assignment when swapping circuit terminations
-* [#6777](https://github.com/netbox-community/netbox/issues/6777) - Fix default value validation for custom text fields
-* [#6778](https://github.com/netbox-community/netbox/issues/6778) - Rack reservation should display rack's location
-* [#6780](https://github.com/netbox-community/netbox/issues/6780) - Include rack location in navigation breadcrumbs
-* [#6794](https://github.com/netbox-community/netbox/issues/6794) - Fix device name display on device status view
-* [#6812](https://github.com/netbox-community/netbox/issues/6812) - Limit reported prefix utilization to 100%
-* [#6822](https://github.com/netbox-community/netbox/issues/6822) - Use consistent maximum value for interface MTU
-
-### Other Changes
-
-* [#6781](https://github.com/netbox-community/netbox/issues/6781) - Database query caching is now disabled by default
-
----
-
-## v2.11.9 (2021-07-08)
-
-### Bug Fixes
-
-* [#6456](https://github.com/netbox-community/netbox/issues/6456) - API schema type should be boolean for `_occupied` on cable termination models
-* [#6710](https://github.com/netbox-community/netbox/issues/6710) - Fix assignment of VM interface parent via REST API
-* [#6714](https://github.com/netbox-community/netbox/issues/6714) - Fix rendering of device type component creation forms
-
----
-
-## v2.11.8 (2021-07-06)
-
-### Enhancements
-
-* [#5503](https://github.com/netbox-community/netbox/issues/5503) - Annotate short date & time fields with their longer form
-* [#6138](https://github.com/netbox-community/netbox/issues/6138) - Add an `empty` filter modifier for character fields
-* [#6200](https://github.com/netbox-community/netbox/issues/6200) - Add rack reservations to global search
-* [#6368](https://github.com/netbox-community/netbox/issues/6368) - Enable virtual chassis assignment during bulk import of devices
-* [#6620](https://github.com/netbox-community/netbox/issues/6620) - Show assigned VMs count under device role view
-* [#6666](https://github.com/netbox-community/netbox/issues/6666) - Show management-only status under interface detail view
-* [#6667](https://github.com/netbox-community/netbox/issues/6667) - Display VM memory as GB/TB as appropriate
-
-### Bug Fixes
-
-* [#6626](https://github.com/netbox-community/netbox/issues/6626) - Fix site field on VM search form; add site group
-* [#6637](https://github.com/netbox-community/netbox/issues/6637) - Fix group assignment in "available VLANs" link under VLAN group view
-* [#6640](https://github.com/netbox-community/netbox/issues/6640) - Disallow numeric values in custom text fields
-* [#6652](https://github.com/netbox-community/netbox/issues/6652) - Fix exception when adding components in bulk to multiple devices
-* [#6676](https://github.com/netbox-community/netbox/issues/6676) - Fix device/VM counts per cluster under cluster type/group views
-* [#6680](https://github.com/netbox-community/netbox/issues/6680) - Allow setting custom field values for VM interfaces on initial creation
-* [#6695](https://github.com/netbox-community/netbox/issues/6695) - Fix exception when importing device type with invalid front port definition
-
----
-
-## v2.11.7 (2021-06-16)
-
-### Enhancements
-
-* [#6455](https://github.com/netbox-community/netbox/issues/6455) - Permit /32 IPv4 and /128 IPv6 prefixes
-* [#6493](https://github.com/netbox-community/netbox/issues/6493) - Show change log diff for non-atomic (pre-2.11) changes
-* [#6564](https://github.com/netbox-community/netbox/issues/6564) - Add N connector type for pass-through ports
-* [#6588](https://github.com/netbox-community/netbox/issues/6588) - Add support for webp files as front/rear device type images
-* [#6589](https://github.com/netbox-community/netbox/issues/6589) - Standardize breadcrumb navigation for power panels and feeds
-
-### Bug Fixes
-
-* [#6553](https://github.com/netbox-community/netbox/issues/6553) - ProviderNetwork search should match on name
-* [#6562](https://github.com/netbox-community/netbox/issues/6562) - Disable ordering of secrets by assigned object
-* [#6563](https://github.com/netbox-community/netbox/issues/6563) - Fix filtering by location for cable connection forms
-* [#6584](https://github.com/netbox-community/netbox/issues/6584) - Fix ordering of nested inventory items
-* [#6602](https://github.com/netbox-community/netbox/issues/6602) - Fix deletion of devices with cables attached
-
----
-
-## v2.11.6 (2021-06-04)
-
-### Bug Fixes
-
-* [#6544](https://github.com/netbox-community/netbox/issues/6544) - Fix migration error when upgrading with VRF(s) defined
-
----
-
-## v2.11.5 (2021-06-04)
-
-**NOTE:** This release includes a database migration that calculates and annotates prefix depth. It may impose a noticeable delay on the upgrade process: Users should anticipate roughly one minute of delay per 100 thousand prefixes being updated.
-
-### Enhancements
-
-* [#6087](https://github.com/netbox-community/netbox/issues/6087) - Improved prefix hierarchy rendering
-* [#6487](https://github.com/netbox-community/netbox/issues/6487) - Add location filter to cable connection form
-* [#6501](https://github.com/netbox-community/netbox/issues/6501) - Expose prefix depth and children on REST API serializer
-* [#6527](https://github.com/netbox-community/netbox/issues/6527) - Support Markdown for report descriptions
-* [#6540](https://github.com/netbox-community/netbox/issues/6540) - Add a "flat" column to the prefix table
-
-### Bug Fixes
-
-* [#6064](https://github.com/netbox-community/netbox/issues/6064) - Fix object permission assignments for user and group models
-* [#6217](https://github.com/netbox-community/netbox/issues/6217) - Disallow passing of string values for integer custom fields
-* [#6284](https://github.com/netbox-community/netbox/issues/6284) - Avoid sending redundant webhooks when adding/removing tags
-* [#6492](https://github.com/netbox-community/netbox/issues/6492) - Correct tag population in post-change data resulting from REST API changes
-* [#6496](https://github.com/netbox-community/netbox/issues/6496) - Fix upgrade script when Python installed in nonstandard path
-* [#6502](https://github.com/netbox-community/netbox/issues/6502) - Correct permissions evaluation for running a report via the REST API
-* [#6517](https://github.com/netbox-community/netbox/issues/6517) - Fix assignment of user when creating rack reservations via REST API
-* [#6525](https://github.com/netbox-community/netbox/issues/6525) - Paginate related IPs table under IP address view
-
----
-
-## v2.11.4 (2021-05-25)
-
-### Enhancements
-
-* [#5121](https://github.com/netbox-community/netbox/issues/5121) - Add content type filters for tags
-* [#6358](https://github.com/netbox-community/netbox/issues/6358) - Add search field for VLAN groups
-* [#6393](https://github.com/netbox-community/netbox/issues/6393) - Add `description` filter for IP addresses
-* [#6400](https://github.com/netbox-community/netbox/issues/6400) - Add cyan color choice for plugin buttons
-* [#6422](https://github.com/netbox-community/netbox/issues/6422) - Enable filtering users by group under admin UI
-* [#6441](https://github.com/netbox-community/netbox/issues/6441) - Improve UI paginator to optimize page object count
-
-### Bug Fixes
-
-* [#6376](https://github.com/netbox-community/netbox/issues/6376) - Fix assignment of VLAN groups to clusters, cluster groups via REST API
-* [#6398](https://github.com/netbox-community/netbox/issues/6398) - Avoid exception when deleting device connected to self via circuit
-* [#6426](https://github.com/netbox-community/netbox/issues/6426) - Allow assigning virtual chassis member interfaces to LAG on VC master
-* [#6438](https://github.com/netbox-community/netbox/issues/6438) - Fix missing descriptions and label for device type imports and exports
-* [#6465](https://github.com/netbox-community/netbox/issues/6465) - Fix typo in installed plugins REST API endpoint
-* [#6467](https://github.com/netbox-community/netbox/issues/6467) - Fix access to metrics on custom `BASE_PATH` when login is required
-* [#6468](https://github.com/netbox-community/netbox/issues/6468) - Disable ordering VLAN groups list by scope object
-
----
-
-## v2.11.3 (2021-05-07)
-
-### Enhancements
-
-* [#6197](https://github.com/netbox-community/netbox/issues/6197) - Introduced `SESSION_COOKIE_NAME` config parameter
-* [#6318](https://github.com/netbox-community/netbox/issues/6318) - Add OM5 MMF cable type
-* [#6351](https://github.com/netbox-community/netbox/issues/6351) - Add aggregates count to tenant view
-* [#6359](https://github.com/netbox-community/netbox/issues/6359) - Enable custom links for organizational and nested group models
-
-### Bug Fixes
-
-* [#6240](https://github.com/netbox-community/netbox/issues/6240) - Fix display of available VLAN ranges under VLAN group view
-* [#6308](https://github.com/netbox-community/netbox/issues/6308) - Fix linking of available VLANs in VLAN group view
-* [#6309](https://github.com/netbox-community/netbox/issues/6309) - Restrict parent VM interface assignment to the parent VM
-* [#6312](https://github.com/netbox-community/netbox/issues/6312) - Interface device filter should return all virtual chassis interfaces only if device is master
-* [#6313](https://github.com/netbox-community/netbox/issues/6313) - Fix device type instance count under manufacturer view
-* [#6321](https://github.com/netbox-community/netbox/issues/6321) - Restore "add an IP" button under prefix IPs view
-* [#6333](https://github.com/netbox-community/netbox/issues/6333) - Fix filtering of circuit terminations by primary key
-* [#6339](https://github.com/netbox-community/netbox/issues/6339) - Improve ordering of interfaces when viewing virtual chassis master
-* [#6350](https://github.com/netbox-community/netbox/issues/6350) - Include first & last IP addresses when allocating available IPv6 addresses via the REST API
-* [#6355](https://github.com/netbox-community/netbox/issues/6355) - Fix caching error when swapping A/Z circuit terminations
-* [#6357](https://github.com/netbox-community/netbox/issues/6357) - Fix ProviderNetwork nested API serializer
-* [#6363](https://github.com/netbox-community/netbox/issues/6363) - Correct pre-population of cluster group when creating a cluster
-* [#6369](https://github.com/netbox-community/netbox/issues/6369) - Fix interface assignment for VLANs in non-scoped groups
-
----
-
-## v2.11.2 (2021-04-27)
-
-### Enhancements
-
-* [#6275](https://github.com/netbox-community/netbox/issues/6275) - Linkify rack, device counts on locations list
-* [#6278](https://github.com/netbox-community/netbox/issues/6278) - Note device locations on cable traces
-* [#6287](https://github.com/netbox-community/netbox/issues/6287) - Add option to clear assigned max length filter on prefixes list
-
-### Bug Fixes
-
-* [#6236](https://github.com/netbox-community/netbox/issues/6236) - Journal entry title should account for configured timezone
-* [#6246](https://github.com/netbox-community/netbox/issues/6246) - Permit full-length descriptions when creating device components and VM interfaces
-* [#6248](https://github.com/netbox-community/netbox/issues/6248) - Fix table column reconfiguration under Chrome
-* [#6252](https://github.com/netbox-community/netbox/issues/6252) - Fix assignment of console port speed values above 19.2kbps
-* [#6254](https://github.com/netbox-community/netbox/issues/6254) - Disable ordering of space column in racks table
-* [#6258](https://github.com/netbox-community/netbox/issues/6258) - Fix parent assignment for SiteGroup API serializer
-* [#6262](https://github.com/netbox-community/netbox/issues/6262) - Support filtering by created/updated time for all relevant objects
-* [#6267](https://github.com/netbox-community/netbox/issues/6267) - Fix cable tracing API endpoint for circuit terminations
-* [#6289](https://github.com/netbox-community/netbox/issues/6289) - Fix assignment of VC member interfaces to LAG interfaces
-
----
-
-## v2.11.1 (2021-04-21)
-
-### Enhancements
-
-* [#6161](https://github.com/netbox-community/netbox/issues/6161) - Enable ordering of device component tables
-* [#6179](https://github.com/netbox-community/netbox/issues/6179) - Enable natural ordering for virtual machines
-* [#6189](https://github.com/netbox-community/netbox/issues/6189) - Add ability to search for locations by name or description
-* [#6190](https://github.com/netbox-community/netbox/issues/6190) - Allow filtering devices with no location assigned
-* [#6210](https://github.com/netbox-community/netbox/issues/6210) - Include child locations on location view
-
-### Bug Fixes
-
-* [#6184](https://github.com/netbox-community/netbox/issues/6184) - Fix parent object table column in prefix IP addresses list
-* [#6188](https://github.com/netbox-community/netbox/issues/6188) - Support custom field filtering for regions, site groups, and locations
-* [#6196](https://github.com/netbox-community/netbox/issues/6196) - Fix object list display for users with read-only permissions
-* [#6215](https://github.com/netbox-community/netbox/issues/6215) - Restore tenancy section in virtual machine form
-
----
-
-## v2.11.0 (2021-04-16)
-
-**Note:** NetBox v2.11 is the last major release that will support Python 3.6. Beginning with NetBox v3.0, Python 3.7 or later will be required.
-
-### Breaking Changes
-
-* All objects now use numeric IDs in their UI view URLs instead of slugs. You may need to update external references to NetBox objects. (Note that this does _not_ affect the REST API.)
-* The UI now uses numeric IDs when filtering object lists. You may need to update external links to filtered object lists. (Note that the slug- and name-based filters will continue to work, however the filter selection fields within the UI will not be automatically populated.)
-* The RackGroup model has been renamed to Location (see [#4971](https://github.com/netbox-community/netbox/issues/4971)). Its REST API endpoint has changed from `/api/dcim/rack-groups/` to `/api/dcim/locations/`.
-* The foreign key field `group` on dcim.Rack has been renamed to `location`.
-* The foreign key field `site` on ipam.VLANGroup has been replaced with the `scope` generic foreign key (see [#5284](https://github.com/netbox-community/netbox/issues/5284)).
-* Custom script ObjectVars no longer support the `queryset` parameter: Use `model` instead (see [#5995](https://github.com/netbox-community/netbox/issues/5995)).
-
-### New Features
-
-#### Journaling Support ([#151](https://github.com/netbox-community/netbox/issues/151))
-
-NetBox now supports journaling for all primary objects. The journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after some time, journal entries persist for the life of the associated object.
-
-#### Parent Interface Assignments ([#1519](https://github.com/netbox-community/netbox/issues/1519))
-
-Virtual device and VM interfaces can now be assigned to a "parent" interface by setting the `parent` field on the interface object. This is helpful for associating subinterfaces with their physical counterpart. For example, you might assign virtual interfaces Gi0/0.100 and Gi0/0.200 as children of the physical interface Gi0/0.
-
-#### Pre- and Post-Change Snapshots in Webhooks ([#3451](https://github.com/netbox-community/netbox/issues/3451))
-
-In conjunction with the newly improved change logging functionality ([#5913](https://github.com/netbox-community/netbox/issues/5913)), outgoing webhooks now include both pre- and post-change representations of the modified object. These are available in the rendering context as a dictionary named `snapshots` with keys `prechange` and `postchange`. For example, here are the abridged snapshots resulting from renaming a site and changing its status:
-
-```json
-"snapshots": {
-    "prechange": {
-        "name": "Site 1",
-        "slug": "site-1",
-        "status": "active",
-        ...
-    },
-    "postchange": {
-        "name": "Site 2",
-        "slug": "site-2",
-        "status": "planned",
-        ...
-    }
-}
-```
-
-Note: The pre-change snapshot for a newly created will always be null, as will the post-change snapshot for a deleted object.
-
-#### Mark as Connected Without a Cable ([#3648](https://github.com/netbox-community/netbox/issues/3648))
-
-Cable termination objects (circuit terminations, power feeds, and most device components) can now be marked as "connected" without actually attaching a cable. This helps simplify the process of modeling an infrastructure boundary where we don't necessarily know or care what is connected to an attachment point, but still need to reflect the termination as being occupied.
-
-In addition to the new `mark_connected` boolean field, the REST API representation of these objects now also includes a read-only boolean field named `_occupied`. This conveniently returns true if either a cable is attached or `mark_connected` is true.
-
-#### Allow Assigning Devices to Locations ([#4971](https://github.com/netbox-community/netbox/issues/4971))
-
-Devices can now be assigned to locations (formerly known as rack groups) within a site without needing to be assigned to a particular rack. This is handy for assigning devices to rooms or floors within a building where racks are not used. The `location` foreign key field has been added to the Device model to support this.
-
-#### Dynamic Object Exports ([#4999](https://github.com/netbox-community/netbox/issues/4999))
-
-When exporting a list of objects in NetBox, users now have the option of selecting the "current view". This will render CSV output matching the current configuration of the table being viewed. For example, if you modify the sites list to display only the site name, tenant, and status, the rendered CSV will include only these columns, and they will appear in the order chosen.
-
-The legacy static export behavior has been retained to ensure backward compatibility for dependent integrations. However, users are strongly encouraged to adapt custom export templates where needed as this functionality will be removed in v3.0.
-
-#### Variable Scope Support for VLAN Groups ([#5284](https://github.com/netbox-community/netbox/issues/5284))
-
-In previous releases, VLAN groups could be assigned only to a site. To afford more flexibility in conveying the true scope of an L2 domain, a VLAN group can now be assigned to a region, site group (new in v2.11), site, location, or rack. VLANs assigned to a group will be available only to devices and virtual machines which exist within its scope.
-
-For example, a VLAN within a group assigned to a location will be available only to devices assigned to that location (or one of its child locations), or to a rack within that location.
-
-#### New Site Group Model ([#5892](https://github.com/netbox-community/netbox/issues/5892))
-
-This release introduces the new SiteGroup model, which can be used to organize sites similar to the existing Region model. Whereas regions are intended for geographically arranging sites into countries, states, and so on, the new site group model can be used to organize sites by functional role or other arbitrary classification. Using regions and site groups in conjunction provides two dimensions along which sites can be organized, offering greater flexibility to the user.
-
-#### Improved Change Logging ([#5913](https://github.com/netbox-community/netbox/issues/5913))
-
-The ObjectChange model (which is used to record the creation, modification, and deletion of NetBox objects) now explicitly records the pre-change and post-change state of each object, rather than only the post-change state. This was done to present a more clear depiction of each change being made, and to prevent the erroneous association of a previous unlogged change with its successor.
-
-#### Provider Network Modeling ([#5986](https://github.com/netbox-community/netbox/issues/5986))
-
-A new provider network model has been introduced to represent the boundary of a network that exists outside the scope of NetBox. Each instance of this model must be assigned to a provider, and circuits can now terminate to either provider networks or to sites. The use of this model will likely be extended by future releases to support overlay and virtual circuit modeling.
-
-### Enhancements
-
-* [#4833](https://github.com/netbox-community/netbox/issues/4833) - Allow assigning config contexts by device type
-* [#5344](https://github.com/netbox-community/netbox/issues/5344) - Add support for custom fields in tables
-* [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
-* [#5375](https://github.com/netbox-community/netbox/issues/5375) - Add `speed` attribute to console port models
-* [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
-* [#5425](https://github.com/netbox-community/netbox/issues/5425) - Create separate tabs for VMs and devices under the cluster view
-* [#5451](https://github.com/netbox-community/netbox/issues/5451) - Add support for multiple-selection custom fields
-* [#5608](https://github.com/netbox-community/netbox/issues/5608) - Add REST API endpoint for custom links
-* [#5610](https://github.com/netbox-community/netbox/issues/5610) - Add REST API endpoint for webhooks
-* [#5757](https://github.com/netbox-community/netbox/issues/5757) - Add unique identifier to every object view
-* [#5830](https://github.com/netbox-community/netbox/issues/5830) - Add `as_attachment` to ExportTemplate to control download behavior
-* [#5848](https://github.com/netbox-community/netbox/issues/5848) - Filter custom fields by content type in format `<app_label>.<model>`
-* [#5891](https://github.com/netbox-community/netbox/issues/5891) - Add `display` field to all REST API serializers
-* [#5894](https://github.com/netbox-community/netbox/issues/5894) - Use primary keys when filtering object lists by related objects in the UI
-* [#5895](https://github.com/netbox-community/netbox/issues/5895) - Rename RackGroup to Location
-* [#5901](https://github.com/netbox-community/netbox/issues/5901) - Add `created` and `last_updated` fields to device component models
-* [#5971](https://github.com/netbox-community/netbox/issues/5971) - Add dedicated views for organizational models
-* [#5972](https://github.com/netbox-community/netbox/issues/5972) - Enable bulk editing for organizational models
-* [#5975](https://github.com/netbox-community/netbox/issues/5975) - Allow partial (decimal) vCPU allocations for virtual machines
-* [#6001](https://github.com/netbox-community/netbox/issues/6001) - Paginate component tables under device views
-* [#6038](https://github.com/netbox-community/netbox/issues/6038) - Include tagged objects list on tag view
-* [#6088](https://github.com/netbox-community/netbox/issues/6088) - Improved table configuration form
-* [#6097](https://github.com/netbox-community/netbox/issues/6097) - Redirect old slug-based object views
-* [#6125](https://github.com/netbox-community/netbox/issues/6125) - Add locations count to home page
-* [#6146](https://github.com/netbox-community/netbox/issues/6146) - Add bulk disconnect support for power feeds
-* [#6149](https://github.com/netbox-community/netbox/issues/6149) - Support image attachments for locations
-
-### Bug Fixes (from v2.11-beta1)
-
-* [#5583](https://github.com/netbox-community/netbox/issues/5583) - Eliminate redundant change records when adding/removing tags
-* [#6100](https://github.com/netbox-community/netbox/issues/6100) - Fix VM interfaces table "add interfaces" link
-* [#6104](https://github.com/netbox-community/netbox/issues/6104) - Fix location column on racks table
-* [#6105](https://github.com/netbox-community/netbox/issues/6105) - Hide checkboxes for VMs under cluster VMs view
-* [#6106](https://github.com/netbox-community/netbox/issues/6106) - Allow assigning a virtual interface as the parent of an existing interface
-* [#6107](https://github.com/netbox-community/netbox/issues/6107) - Fix rack selection field on device form
-* [#6110](https://github.com/netbox-community/netbox/issues/6110) - Fix handling of TemplateColumn values for table export
-* [#6123](https://github.com/netbox-community/netbox/issues/6123) - Prevent device from being assigned to mismatched site and location
-* [#6124](https://github.com/netbox-community/netbox/issues/6124) - Location `parent` filter should return all child locations (not just those directly assigned)
-* [#6130](https://github.com/netbox-community/netbox/issues/6130) - Improve display of assigned models in custom fields list
-* [#6155](https://github.com/netbox-community/netbox/issues/6155) - Fix admin links for plugins, background tasks
-* [#6171](https://github.com/netbox-community/netbox/issues/6171) - Fix display of horizontally-scrolling object lists
-* [#6173](https://github.com/netbox-community/netbox/issues/6173) - Fix assigned device/VM count when bulk editing/deleting device roles
-* [#6176](https://github.com/netbox-community/netbox/issues/6176) - Correct position of MAC address field when creating VM interfaces
-* [#6177](https://github.com/netbox-community/netbox/issues/6177) - Prevent VM interface from being assigned as its own parent
-
-### Other Changes
-
-* [#1638](https://github.com/netbox-community/netbox/issues/1638) - Migrate all primary keys to 64-bit integers
-* [#5873](https://github.com/netbox-community/netbox/issues/5873) - Use numeric IDs in all object URLs
-* [#5938](https://github.com/netbox-community/netbox/issues/5938) - Deprecated support for Python 3.6
-* [#5990](https://github.com/netbox-community/netbox/issues/5990) - Deprecated `display_field` parameter for custom script ObjectVar and MultiObjectVar fields
-* [#5995](https://github.com/netbox-community/netbox/issues/5995) - Dropped backward compatibility for `queryset` parameter on ObjectVar and MultiObjectVar (use `model` instead)
-* [#6014](https://github.com/netbox-community/netbox/issues/6014) - Moved the virtual machine interfaces list to a separate view
-* [#6071](https://github.com/netbox-community/netbox/issues/6071) - Cable traces now traverse circuits
-
-### REST API Changes
-
-* All primary keys are now 64-bit integers
-* All model serializers now include a `display` field to be used for the presentation of an object to a human user
-* All device components
-    * Added support for custom fields
-    * Added `created` and `last_updated` fields to track object creation and modification
-* All device component templates
-    * Added `created` and `last_updated` fields to track object creation and modification
-* All organizational models
-    * Added support for custom fields
-* All cable termination models (cabled device components, power feeds, and circuit terminations)
-    * Added `mark_connected` boolean field to force connection status
-    * Added `_occupied` read-only boolean field as common attribute for determining whether an object is occupied
-* Renamed RackGroup to Location
-    * The `/dcim/rack-groups/` endpoint is now `/dcim/locations/`
-* circuits.CircuitTermination
-    * Added the `provider_network` field
-    * Removed the `connected_endpoint`, `connected_endpoint_type`, and `connected_endpoint_reachable` fields
-    * The `trace/` endpoint has been replaced with `paths/`
-* circuits.ProviderNetwork
-    * Added the `/api/circuits/provider-networks/` endpoint
-* dcim.Device
-    * Added the `location` field
-* dcim.Interface
-    * Added the `parent` field
-* dcim.PowerPanel
-    * Renamed `rack_group` field to `location`
-* dcim.Rack
-    * Renamed `group` field to `location`
-* dcim.Site
-    * Added the `group` foreign key field to SiteGroup
-* dcim.SiteGroup
-    * Added the `/api/dcim/site-groups/` endpoint
-* extras.ConfigContext
-    * Added the `site_groups` many-to-many field to track the assignment of ConfigContexts to SiteGroups
-* extras.CustomField
-    * Added new custom field type: `multi-select`
-* extras.CustomLink
-    * Added the `/api/extras/custom-links/` endpoint
-* extras.ExportTemplate
-    * Added the `as_attachment` boolean field
-* extras.ObjectChange
-    * Added the `prechange_data` field
-    * Renamed `object_data` to `postchange_data`
-* extras.Webhook
-    * Added the `/api/extras/webhooks/` endpoint
-* ipam.VLANGroup
-    * Added the `scope_type`, `scope_id`, and `scope` fields (`scope` is a generic foreign key)
-    * Dropped the `site` foreign key field
-* virtualization.VirtualMachine
-    * `vcpus` has been changed from an integer to a decimal value
-* virtualization.VMInterface
-    * Added the `parent` field

+ 0 - 227
docs/release-notes/version-2.2.md

@@ -1,227 +0,0 @@
-# NetBox v2.2 Release Notes
-
-## v2.2.10 (2018-02-21)
-
-### Enhancements
-
-* [#78](https://github.com/netbox-community/netbox/issues/78) - Extended topology maps to support console and power connections
-* [#1693](https://github.com/netbox-community/netbox/issues/1693) - Allow specifying loose or exact matching for custom field filters
-* [#1714](https://github.com/netbox-community/netbox/issues/1714) - Standardized CSV export functionality for all object lists
-* [#1876](https://github.com/netbox-community/netbox/issues/1876) - Added explanatory title text to disabled NAPALM buttons on device view
-* [#1885](https://github.com/netbox-community/netbox/issues/1885) - Added a device filter field for primary IP
-
-### Bug Fixes
-
-* [#1858](https://github.com/netbox-community/netbox/issues/1858) - Include device/VM count for cluster list in global search results
-* [#1859](https://github.com/netbox-community/netbox/issues/1859) - Implemented support for line breaks within CSV fields
-* [#1860](https://github.com/netbox-community/netbox/issues/1860) - Do not populate initial values for custom fields when editing objects in bulk
-* [#1869](https://github.com/netbox-community/netbox/issues/1869) - Corrected ordering of VRFs with duplicate names
-* [#1886](https://github.com/netbox-community/netbox/issues/1886) - Allow setting the primary IPv4/v6 address for a virtual machine via the web UI
-
----
-
-## v2.2.9 (2018-01-31)
-
-### Enhancements
-
-* [#144](https://github.com/netbox-community/netbox/issues/144) - Implemented bulk import/edit/delete views for InventoryItems
-* [#1073](https://github.com/netbox-community/netbox/issues/1073) - Include prefixes/IPs from all VRFs when viewing the children of a container prefix in the global table
-* [#1366](https://github.com/netbox-community/netbox/issues/1366) - Enable searching for regions by name/slug
-* [#1406](https://github.com/netbox-community/netbox/issues/1406) - Display tenant description as title text in object tables
-* [#1824](https://github.com/netbox-community/netbox/issues/1824) - Add virtual machine count to platforms list
-* [#1835](https://github.com/netbox-community/netbox/issues/1835) - Consistent positioning of previous/next rack buttons
-
-### Bug Fixes
-
-* [#1621](https://github.com/netbox-community/netbox/issues/1621) - Tweaked LLDP interface name evaluation logic
-* [#1765](https://github.com/netbox-community/netbox/issues/1765) - Improved rendering of null options for model choice fields in filter forms
-* [#1807](https://github.com/netbox-community/netbox/issues/1807) - Populate VRF from parent when creating a new prefix
-* [#1809](https://github.com/netbox-community/netbox/issues/1809) - Populate tenant assignment from parent when creating a new prefix
-* [#1818](https://github.com/netbox-community/netbox/issues/1818) - InventoryItem API serializer no longer requires specifying a null value for items with no parent
-* [#1845](https://github.com/netbox-community/netbox/issues/1845) - Correct display of VMs in list with no role assigned
-* [#1850](https://github.com/netbox-community/netbox/issues/1850) - Fix TypeError when attempting IP address import if only unnamed devices exist
-
----
-
-## v2.2.8 (2017-12-20)
-
-### Enhancements
-
-* [#1771](https://github.com/netbox-community/netbox/issues/1771) - Added name filter for racks
-* [#1772](https://github.com/netbox-community/netbox/issues/1772) - Added position filter for devices
-* [#1773](https://github.com/netbox-community/netbox/issues/1773) - Moved child prefixes table to its own view
-* [#1774](https://github.com/netbox-community/netbox/issues/1774) - Include a button to refine search results for all object types under global search
-* [#1784](https://github.com/netbox-community/netbox/issues/1784) - Added `cluster_type` filters for virtual machines
-
-### Bug Fixes
-
-* [#1766](https://github.com/netbox-community/netbox/issues/1766) - Fixed display of "select all" button on device power outlets list
-* [#1767](https://github.com/netbox-community/netbox/issues/1767) - Use proper template for 404 responses
-* [#1778](https://github.com/netbox-community/netbox/issues/1778) - Preserve initial VRF assignment when adding IP addresses in bulk from a prefix
-* [#1783](https://github.com/netbox-community/netbox/issues/1783) - Added `vm_role` filter for device roles
-* [#1785](https://github.com/netbox-community/netbox/issues/1785) - Omit filter forms from browsable API
-* [#1787](https://github.com/netbox-community/netbox/issues/1787) - Added missing site field to virtualization cluster CSV export
-
----
-
-## v2.2.7 (2017-12-07)
-
-### Enhancements
-
-* [#1722](https://github.com/netbox-community/netbox/issues/1722) - Added virtual machine count to site view
-* [#1737](https://github.com/netbox-community/netbox/issues/1737) - Added a `contains` API filter to find all prefixes containing a given IP or prefix
-
-### Bug Fixes
-
-* [#1712](https://github.com/netbox-community/netbox/issues/1712) - Corrected tenant inheritance for new IP addresses created from a parent prefix
-* [#1721](https://github.com/netbox-community/netbox/issues/1721) - Differentiated child IP count from utilization percentage for prefixes
-* [#1740](https://github.com/netbox-community/netbox/issues/1740) - Delete session_key cookie on logout
-* [#1741](https://github.com/netbox-community/netbox/issues/1741) - Fixed Unicode support for secret plaintexts
-* [#1743](https://github.com/netbox-community/netbox/issues/1743) - Include number of instances for device types in global search
-* [#1751](https://github.com/netbox-community/netbox/issues/1751) - Corrected filtering for IPv6 addresses containing letters
-* [#1756](https://github.com/netbox-community/netbox/issues/1756) - Improved natural ordering of console server ports and power outlets
-
----
-
-## v2.2.6 (2017-11-16)
-
-### Enhancements
-
-* [#1669](https://github.com/netbox-community/netbox/issues/1669) - Clicking "add an IP" from the prefix view will default to the first available IP within the prefix
-
-### Bug Fixes
-
-* [#1397](https://github.com/netbox-community/netbox/issues/1397) - Display global search in navigation menu unless display is less than 1200px wide
-* [#1599](https://github.com/netbox-community/netbox/issues/1599) - Reduce mobile cut-off for navigation menu to 960px
-* [#1715](https://github.com/netbox-community/netbox/issues/1715) - Added missing import buttons on object lists
-* [#1717](https://github.com/netbox-community/netbox/issues/1717) - Fixed interface validation for virtual machines
-* [#1718](https://github.com/netbox-community/netbox/issues/1718) - Set empty label to "Global" or VRF field in IP assignment form
-
----
-
-## v2.2.5 (2017-11-14)
-
-### Enhancements
-
-* [#1512](https://github.com/netbox-community/netbox/issues/1512) - Added a view to search for an IP address being assigned to an interface
-* [#1679](https://github.com/netbox-community/netbox/issues/1679) - Added IP address roles to device/VM interface lists
-* [#1683](https://github.com/netbox-community/netbox/issues/1683) - Replaced default 500 handler with custom middleware to provide preliminary troubleshooting assistance
-* [#1684](https://github.com/netbox-community/netbox/issues/1684) - Replaced prefix `parent` filter with `within` and `within_include`
-
-### Bug Fixes
-
-* [#1471](https://github.com/netbox-community/netbox/issues/1471) - Correct bulk selection of IP addresses within a prefix assigned to a VRF
-* [#1642](https://github.com/netbox-community/netbox/issues/1642) - Validate device type classification when creating console server ports and power outlets
-* [#1650](https://github.com/netbox-community/netbox/issues/1650) - Correct numeric ordering for interfaces with no alphabetic type
-* [#1676](https://github.com/netbox-community/netbox/issues/1676) - Correct filtering of child prefixes upon bulk edit/delete from the parent prefix view
-* [#1689](https://github.com/netbox-community/netbox/issues/1689) - Disregard IP address mask when filtering for child IPs of a prefix
-* [#1696](https://github.com/netbox-community/netbox/issues/1696) - Fix for NAPALM v2.0+
-* [#1699](https://github.com/netbox-community/netbox/issues/1699) - Correct nested representation in the API of primary IPs for virtual machines and add missing primary_ip property
-* [#1701](https://github.com/netbox-community/netbox/issues/1701) - Fixed validation in `extras/0008_reports.py` migration for certain versions of PostgreSQL
-* [#1703](https://github.com/netbox-community/netbox/issues/1703) - Added API serializer validation for custom integer fields
-* [#1705](https://github.com/netbox-community/netbox/issues/1705) - Fixed filtering of devices with a status of offline
-
----
-
-## v2.2.4 (2017-10-31)
-
-### Bug Fixes
-
-* [#1670](https://github.com/netbox-community/netbox/issues/1670) - Fixed server error when calling certain filters (regression from #1649)
-
----
-
-## v2.2.3 (2017-10-31)
-
-### Enhancements
-
-* [#999](https://github.com/netbox-community/netbox/issues/999) - Display devices on which circuits are terminated in circuits list
-* [#1491](https://github.com/netbox-community/netbox/issues/1491) - Added initial data for the virtualization app
-* [#1620](https://github.com/netbox-community/netbox/issues/1620) - Loosen IP address search filter to match all IPs that start with the given string
-* [#1631](https://github.com/netbox-community/netbox/issues/1631) - Added a `post_run` method to the Report class
-* [#1666](https://github.com/netbox-community/netbox/issues/1666) - Allow modifying the owner of a rack reservation
-
-### Bug Fixes
-
-* [#1513](https://github.com/netbox-community/netbox/issues/1513) - Correct filtering of custom field choices
-* [#1603](https://github.com/netbox-community/netbox/issues/1603) - Hide selection checkboxes for tables with no available actions
-* [#1618](https://github.com/netbox-community/netbox/issues/1618) - Allow bulk deletion of all virtual machines
-* [#1619](https://github.com/netbox-community/netbox/issues/1619) - Correct text-based filtering of IP network and address fields
-* [#1624](https://github.com/netbox-community/netbox/issues/1624) - Add VM count to device roles table
-* [#1634](https://github.com/netbox-community/netbox/issues/1634) - Cluster should not be a required field when importing child devices
-* [#1649](https://github.com/netbox-community/netbox/issues/1649) - Correct filtering on null values (e.g. ?tenant_id=0) for django-filters v1.1.0+
-* [#1653](https://github.com/netbox-community/netbox/issues/1653) - Remove outdated description for DeviceType's `is_network_device` flag
-* [#1664](https://github.com/netbox-community/netbox/issues/1664) - Added missing `serial` field in default rack CSV export
-
----
-
-## v2.2.2 (2017-10-17)
-
-### Enhancements
-
-* [#1580](https://github.com/netbox-community/netbox/issues/1580) - Allow cluster assignment when bulk importing devices
-* [#1587](https://github.com/netbox-community/netbox/issues/1587) - Add primary IP column for virtual machines in global search results
-
-### Bug Fixes
-
-* [#1498](https://github.com/netbox-community/netbox/issues/1498) - Avoid duplicating nodes when generating topology maps
-* [#1579](https://github.com/netbox-community/netbox/issues/1579) - Devices already assigned to a cluster cannot be added to a different cluster
-* [#1582](https://github.com/netbox-community/netbox/issues/1582) - Add `virtual_machine` attribute to IPAddress
-* [#1584](https://github.com/netbox-community/netbox/issues/1584) - Colorized virtual machine role column
-* [#1585](https://github.com/netbox-community/netbox/issues/1585) - Fixed slug-based filtering of virtual machines
-* [#1605](https://github.com/netbox-community/netbox/issues/1605) - Added clusters and virtual machines to object list for global search
-* [#1609](https://github.com/netbox-community/netbox/issues/1609) - Added missing `virtual_machine` field to IP address interface serializer
-
----
-
-## v2.2.1 (2017-10-12)
-
-### Bug Fixes
-
-* [#1576](https://github.com/netbox-community/netbox/issues/1576) - Moved PostgreSQL validation logic into the relevant migration (fixed ImproperlyConfigured exception on init)
-
----
-
-## v2.2.0 (2017-10-12)
-
-**Note:** This release requires PostgreSQL 9.4 or higher. Do not attempt to upgrade unless you are running at least PostgreSQL 9.4.
-
-**Note:** The release replaces the deprecated pycrypto library with [pycryptodome](https://github.com/Legrandin/pycryptodome). The upgrade script has been extended to automatically uninstall the old library, but please verify your installed packages with `pip freeze | grep pycrypto` if you run into problems.
-
-### New Features
-
-#### Virtual Machines and Clusters ([#142](https://github.com/netbox-community/netbox/issues/142))
-
-Our second-most popular feature request has arrived! NetBox now supports the creation of virtual machines, which can be assigned virtual interfaces and IP addresses. VMs are arranged into clusters, each of which has a type and (optionally) a group.
-
-#### Custom Validation Reports ([#1511](https://github.com/netbox-community/netbox/issues/1511))
-
-Users can now create custom reports which are run to validate data in NetBox. Reports work very similar to Python unit tests: Each report inherits from NetBox's Report class and contains one or more test method. Reports can be run and retrieved via the web UI, API, or CLI. See [the docs](https://docs.netbox.dev/en/stable/miscellaneous/reports/) for more info.
-
-### Enhancements
-
-* [#494](https://github.com/netbox-community/netbox/issues/494) - Include asset tag in device info pop-up on rack elevation
-* [#1444](https://github.com/netbox-community/netbox/issues/1444) - Added a `serial` field to the rack model
-* [#1479](https://github.com/netbox-community/netbox/issues/1479) - Added an IP address role for CARP
-* [#1506](https://github.com/netbox-community/netbox/issues/1506) - Extended rack facility ID field from 30 to 50 characters
-* [#1510](https://github.com/netbox-community/netbox/issues/1510) - Added ability to search by name when adding devices to a cluster
-* [#1527](https://github.com/netbox-community/netbox/issues/1527) - Replace deprecated pycrypto library with pycryptodome
-* [#1551](https://github.com/netbox-community/netbox/issues/1551) - Added API endpoints listing static field choices for each app
-* [#1556](https://github.com/netbox-community/netbox/issues/1556) - Added CPAK, CFP2, and CFP4 100GE interface form factors
-* Added CSV import views for all object types
-
-### Bug Fixes
-
-* [#1550](https://github.com/netbox-community/netbox/issues/1550) - Corrected interface connections link in navigation menu
-* [#1554](https://github.com/netbox-community/netbox/issues/1554) - Don't require form_factor when creating an interface assigned to a virtual machine
-* [#1557](https://github.com/netbox-community/netbox/issues/1557) - Added filtering for virtual machine interfaces
-* [#1567](https://github.com/netbox-community/netbox/issues/1567) - Prompt user for session key when importing secrets
-
-### API Changes
-
-* Introduced the virtualization app and its associated endpoints at `/api/virtualization`
-* Added the `/api/extras/reports` endpoint for fetching and running reports
-* The `ipam.Service` and `dcim.Interface` models now have a `virtual_machine` field in addition to the `device` field. Only one of the two fields may be defined for each object
-* Added a `vm_role` field to `dcim.DeviceRole`, which indicates whether a role is suitable for assigned to a virtual machine
-* Added a `serial` field to 'dcim.Rack` for serial numbers
-* Each app now has a `_choices` endpoint, which lists the available options for all model field with static choices (e.g. interface form factors)

+ 0 - 225
docs/release-notes/version-2.3.md

@@ -1,225 +0,0 @@
-# NetBox v2.3 Release Notes
-
-## v2.3.7 (2018-07-26)
-
-### Enhancements
-
-* [#2166](https://github.com/netbox-community/netbox/issues/2166) - Enable partial matching on device asset_tag during search
-
-### Bug Fixes
-
-* [#1977](https://github.com/netbox-community/netbox/issues/1977) - Fixed exception when creating a virtual chassis with a non-master device in position 1
-* [#1992](https://github.com/netbox-community/netbox/issues/1992) - Isolate errors when one of multiple NAPALM methods fails
-* [#2202](https://github.com/netbox-community/netbox/issues/2202) - Ditched half-baked concept of tenancy inheritance via VRF
-* [#2222](https://github.com/netbox-community/netbox/issues/2222) - IP addresses created via the `available-ips` API endpoint should have the same mask as their parent prefix (not /32)
-* [#2231](https://github.com/netbox-community/netbox/issues/2231) - Remove `get_absolute_url()` from DeviceRole (can apply to devices or VMs)
-* [#2250](https://github.com/netbox-community/netbox/issues/2250) - Include stat counters on report result navigation
-* [#2255](https://github.com/netbox-community/netbox/issues/2255) - Corrected display of results in reports list
-* [#2256](https://github.com/netbox-community/netbox/issues/2256) - Prevent navigation menu overlap when jumping to test results on report page
-* [#2257](https://github.com/netbox-community/netbox/issues/2257) - Corrected casting of RIR utilization stats as floats
-* [#2266](https://github.com/netbox-community/netbox/issues/2266) - Permit additional logging of exceptions beyond custom middleware
-
----
-
-## v2.3.6 (2018-07-16)
-
-### Enhancements
-
-* [#2107](https://github.com/netbox-community/netbox/issues/2107) - Added virtual chassis to global search
-* [#2125](https://github.com/netbox-community/netbox/issues/2125) - Show child status in device bay list
-
-### Bug Fixes
-
-* [#2214](https://github.com/netbox-community/netbox/issues/2214) - Error when assigning a VLAN to an interface on a VM in a cluster with no assigned site
-* [#2239](https://github.com/netbox-community/netbox/issues/2239) - Pin django-filter to version 1.1.0
-
----
-
-## v2.3.5 (2018-07-02)
-
-### Enhancements
-
-* [#2159](https://github.com/netbox-community/netbox/issues/2159) - Allow custom choice field to specify a default choice
-* [#2177](https://github.com/netbox-community/netbox/issues/2177) - Include device serial number in rack elevation pop-up
-* [#2194](https://github.com/netbox-community/netbox/issues/2194) - Added `address` filter to IPAddress model
-
-### Bug Fixes
-
-* [#1826](https://github.com/netbox-community/netbox/issues/1826) - Corrected description of security parameters under API definition
-* [#2021](https://github.com/netbox-community/netbox/issues/2021) - Fix recursion error when viewing API docs under Python 3.4
-* [#2064](https://github.com/netbox-community/netbox/issues/2064) - Disable calls to online swagger validator
-* [#2173](https://github.com/netbox-community/netbox/issues/2173) - Fixed IndexError when automatically allocating IP addresses from large IPv6 prefixes
-* [#2181](https://github.com/netbox-community/netbox/issues/2181) - Raise validation error on invalid `prefix_length` when allocating next-available prefix
-* [#2182](https://github.com/netbox-community/netbox/issues/2182) - ValueError can be raised when viewing the interface connections table
-* [#2191](https://github.com/netbox-community/netbox/issues/2191) - Added missing static choices to circuits and DCIM API endpoints
-* [#2192](https://github.com/netbox-community/netbox/issues/2192) - Prevent a 0U device from being assigned to a rack position
-
----
-
-## v2.3.4 (2018-06-07)
-
-### Bug Fixes
-
-* [#2066](https://github.com/netbox-community/netbox/issues/2066) - Catch `AddrFormatError` exception on invalid IP addresses
-* [#2075](https://github.com/netbox-community/netbox/issues/2075) - Enable tenant assignment when creating a rack reservation via the API
-* [#2083](https://github.com/netbox-community/netbox/issues/2083) - Add missing export button to rack roles list view
-* [#2087](https://github.com/netbox-community/netbox/issues/2087) - Don't overwrite existing vc_position of master device when creating a virtual chassis
-* [#2093](https://github.com/netbox-community/netbox/issues/2093) - Fix link to circuit termination in device interfaces table
-* [#2097](https://github.com/netbox-community/netbox/issues/2097) - Fixed queryset-based bulk deletion of clusters and regions
-* [#2098](https://github.com/netbox-community/netbox/issues/2098) - Fixed missing checkboxes for host devices in cluster view
-* [#2127](https://github.com/netbox-community/netbox/issues/2127) - Prevent non-conntectable interfaces from being connected
-* [#2143](https://github.com/netbox-community/netbox/issues/2143) - Accept null value for empty time zone field
-* [#2148](https://github.com/netbox-community/netbox/issues/2148) - Do not force timezone selection when editing sites in bulk
-* [#2150](https://github.com/netbox-community/netbox/issues/2150) - Fix display of LLDP neighbors when interface name contains a colon
-
----
-
-## v2.3.3 (2018-04-19)
-
-### Enhancements
-
-* [#1990](https://github.com/netbox-community/netbox/issues/1990) - Improved search function when assigning an IP address to an interface
-
-### Bug Fixes
-
-* [#1975](https://github.com/netbox-community/netbox/issues/1975) - Correct filtering logic for custom boolean fields
-* [#1988](https://github.com/netbox-community/netbox/issues/1988) - Order interfaces naturally when bulk renaming
-* [#1993](https://github.com/netbox-community/netbox/issues/1993) - Corrected status choices in site CSV import form
-* [#1999](https://github.com/netbox-community/netbox/issues/1999) - Added missing description field to site edit form
-* [#2012](https://github.com/netbox-community/netbox/issues/2012) - Fixed deselection of an IP address as the primary IP for its parent device/VM
-* [#2014](https://github.com/netbox-community/netbox/issues/2014) - Allow assignment of VLANs to VM interfaces via the API
-* [#2019](https://github.com/netbox-community/netbox/issues/2019) - Avoid casting oversized numbers as integers
-* [#2022](https://github.com/netbox-community/netbox/issues/2022) - Show 0 for zero-value fields on CSV export
-* [#2023](https://github.com/netbox-community/netbox/issues/2023) - Manufacturer should not be a required field when importing platforms
-* [#2037](https://github.com/netbox-community/netbox/issues/2037) - Fixed IndexError exception when attempting to create a new rack reservation
-
----
-
-## v2.3.2 (2018-03-22)
-
-### Enhancements
-
-* [#1586](https://github.com/netbox-community/netbox/issues/1586) - Extend bulk interface creation to support alphanumeric characters
-* [#1866](https://github.com/netbox-community/netbox/issues/1866) - Introduced AnnotatedMultipleChoiceField for filter forms
-* [#1930](https://github.com/netbox-community/netbox/issues/1930) - Switched to drf-yasg for Swagger API documentation
-* [#1944](https://github.com/netbox-community/netbox/issues/1944) - Enable assigning VLANs to virtual machine interfaces
-* [#1945](https://github.com/netbox-community/netbox/issues/1945) - Implemented a VLAN members view
-* [#1949](https://github.com/netbox-community/netbox/issues/1949) - Added a button to view elevations on rack groups list
-* [#1952](https://github.com/netbox-community/netbox/issues/1952) - Implemented a more robust mechanism for assigning VLANs to interfaces
-
-### Bug Fixes
-
-* [#1948](https://github.com/netbox-community/netbox/issues/1948) - Fix TypeError when attempting to add a member to an existing virtual chassis
-* [#1951](https://github.com/netbox-community/netbox/issues/1951) - Fix TypeError exception when importing platforms
-* [#1953](https://github.com/netbox-community/netbox/issues/1953) - Ignore duplicate IPs when calculating prefix utilization
-* [#1955](https://github.com/netbox-community/netbox/issues/1955) - Require a plaintext value when creating a new secret
-* [#1978](https://github.com/netbox-community/netbox/issues/1978) - Include all virtual chassis member interfaces in LLDP neighbors view
-* [#1980](https://github.com/netbox-community/netbox/issues/1980) - Fixed bug when trying to nullify a selection custom field under Python 2
-
----
-
-## v2.3.1 (2018-03-01)
-
-### Enhancements
-
-* [#1910](https://github.com/netbox-community/netbox/issues/1910) - Added filters for cluster group and cluster type
-
-### Bug Fixes
-
-* [#1915](https://github.com/netbox-community/netbox/issues/1915) - Redirect to device view after deleting a component
-* [#1919](https://github.com/netbox-community/netbox/issues/1919) - Prevent exception when attempting to create a virtual machine without selecting devices
-* [#1921](https://github.com/netbox-community/netbox/issues/1921) - Ignore ManyToManyFields when validating a new object created via the API
-* [#1924](https://github.com/netbox-community/netbox/issues/1924) - Include VID in VLAN lists when editing an interface
-* [#1926](https://github.com/netbox-community/netbox/issues/1926) - Prevent reassignment of parent device when bulk editing VC member interfaces
-* [#1927](https://github.com/netbox-community/netbox/issues/1927) - Include all VC member interfaces on A side when creating a new interface connection
-* [#1928](https://github.com/netbox-community/netbox/issues/1928) - Fixed form validation when modifying VLANs assigned to an interface
-* [#1934](https://github.com/netbox-community/netbox/issues/1934) - Fixed exception when rendering export template on an object type with custom fields assigned
-* [#1935](https://github.com/netbox-community/netbox/issues/1935) - Correct API validation of VLANs assigned to interfaces
-* [#1936](https://github.com/netbox-community/netbox/issues/1936) - Trigger validation error when attempting to create a virtual chassis without specifying member positions
-
----
-
-## v2.3.0 (2018-02-26)
-
-### New Features
-
-#### Virtual Chassis ([#99](https://github.com/netbox-community/netbox/issues/99))
-
-A virtual chassis represents a set of physical devices with a shared control plane; for example, a stack of switches managed as a single device. Viewing the master device of a virtual chassis will show all member interfaces and IP addresses.
-
-#### Interface VLAN Assignments ([#150](https://github.com/netbox-community/netbox/issues/150))
-
-Interfaces can now be assigned an 802.1Q mode (access or trunked) and associated with particular VLANs. Thanks to [John Anderson](https://github.com/lampwins) for his work on this!
-
-#### Bulk Object Creation via the API ([#1553](https://github.com/netbox-community/netbox/issues/1553))
-
-The REST API now supports the creation of multiple objects of the same type using a single POST request. For example, to create multiple devices:
-
-```
-curl -X POST -H "Authorization: Token <TOKEN>" -H "Content-Type: application/json" -H "Accept: application/json; indent=4" http://localhost:8000/api/dcim/devices/ --data '[
-{"name": "device1", "device_type": 24, "device_role": 17, "site": 6},
-{"name": "device2", "device_type": 24, "device_role": 17, "site": 6},
-{"name": "device3", "device_type": 24, "device_role": 17, "site": 6},
-]'
-```
-
-Bulk creation is all-or-none: If any of the creations fails, the entire operation is rolled back.
-
-#### Automatic Provisioning of Next Available Prefixes ([#1694](https://github.com/netbox-community/netbox/issues/1694))
-
-Similar to IP addresses, NetBox now supports automated provisioning of available prefixes from within a parent prefix. For example, to retrieve the next three available /28s within a parent /24:
-
-```
-curl -X POST -H "Authorization: Token <TOKEN>" -H "Content-Type: application/json" -H "Accept: application/json; indent=4" http://localhost:8000/api/ipam/prefixes/10153/available-prefixes/ --data '[
-{"prefix_length": 28},
-{"prefix_length": 28},
-{"prefix_length": 28}
-]'
-```
-
-If the parent prefix cannot accommodate all requested prefixes, the operation is cancelled and no new prefixes are created.
-
-#### Bulk Renaming of Device/VM Components ([#1781](https://github.com/netbox-community/netbox/issues/1781))
-
-Device components (interfaces, console ports, etc.) can now be renamed in bulk via the web interface. This was implemented primarily to support the bulk renumbering of interfaces whose parent is part of a virtual chassis.
-
-### Enhancements
-
-* [#1283](https://github.com/netbox-community/netbox/issues/1283) - Added a `time_zone` field to the site model
-* [#1321](https://github.com/netbox-community/netbox/issues/1321) - Added `created` and `last_updated` fields for relevant models to their API serializers
-* [#1553](https://github.com/netbox-community/netbox/issues/1553) - Introduced support for bulk object creation via the API
-* [#1592](https://github.com/netbox-community/netbox/issues/1592) - Added tenancy assignment for rack reservations
-* [#1744](https://github.com/netbox-community/netbox/issues/1744) - Allow associating a platform with a specific manufacturer
-* [#1758](https://github.com/netbox-community/netbox/issues/1758) - Added a `status` field to the site model
-* [#1821](https://github.com/netbox-community/netbox/issues/1821) - Added a `description` field to the site model
-* [#1864](https://github.com/netbox-community/netbox/issues/1864) - Added a `status` field to the circuit model
-
-### Bug Fixes
-
-* [#1136](https://github.com/netbox-community/netbox/issues/1136) - Enforce model validation during bulk update
-* [#1645](https://github.com/netbox-community/netbox/issues/1645) - Simplified interface serialzier for IP addresses and optimized API view queryset
-* [#1838](https://github.com/netbox-community/netbox/issues/1838) - Fix KeyError when attempting to create a VirtualChassis with no devices selected
-* [#1847](https://github.com/netbox-community/netbox/issues/1847) - RecursionError when a virtual chasis master device has no name
-* [#1848](https://github.com/netbox-community/netbox/issues/1848) - Allow null value for interface encapsulation mode
-* [#1867](https://github.com/netbox-community/netbox/issues/1867) - Allow filtering on device status with multiple values
-* [#1881](https://github.com/netbox-community/netbox/issues/1881)* - Fixed bulk editing of interface 802.1Q settings
-* [#1884](https://github.com/netbox-community/netbox/issues/1884)* - Provide additional context to identify devices when creating/editing a virtual chassis
-* [#1907](https://github.com/netbox-community/netbox/issues/1907) - Allow removing an IP as the primary for a device when editing the IP directly
-
-\* New since v2.3-beta2
-
-### Breaking Changes
-
-* Constants representing device status have been renamed for clarity (for example, `STATUS_ACTIVE` is now `DEVICE_STATUS_ACTIVE`). Custom validation reports will need to be updated if they reference any of these constants.
-
-### API Changes
-
-* API creation calls now accept either a single JSON object or a list of JSON objects. If multiple objects are passed and one or more them fail validation, no objects will be created.
-* Added `created` and `last_updated` fields for objects inheriting from CreatedUpdatedModel.
-* Removed the `parent` filter for prefixes (use `within` or `within_include` instead).
-* The IP address serializer now includes only a minimal nested representation of the assigned interface (if any) and its parent device or virtual machine.
-* The rack reservation serializer now includes a nested representation of its owning user (as well as the assigned tenant, if any).
-* Added endpoints for virtual chassis and VC memberships.
-* Added `status`, `time_zone` (pytz format), and `description` fields to dcim.Site.
-* Added a `manufacturer` foreign key field on dcim.Platform.
-* Added a `status` field on circuits.Circuit.

+ 0 - 234
docs/release-notes/version-2.4.md

@@ -1,234 +0,0 @@
-# NetBox v2.4 Release Notes
-
-## v2.4.9 (2018-12-07)
-
-### Enhancements
-
-* [#2089](https://github.com/netbox-community/netbox/issues/2089) - Add SONET interface form factors
-* [#2495](https://github.com/netbox-community/netbox/issues/2495) - Enable deep-merging of config context data
-* [#2597](https://github.com/netbox-community/netbox/issues/2597) - Add FibreChannel SFP28 (32GFC) interface form factor
-
-### Bug Fixes
-
-* [#2400](https://github.com/netbox-community/netbox/issues/2400) - Correct representation of nested object assignment in API docs
-* [#2576](https://github.com/netbox-community/netbox/issues/2576) - Correct type for count_* fields in site API representation
-* [#2606](https://github.com/netbox-community/netbox/issues/2606) - Fixed filtering for interfaces with a virtual form factor
-* [#2611](https://github.com/netbox-community/netbox/issues/2611) - Fix error handling when assigning a clustered device to a different site
-* [#2613](https://github.com/netbox-community/netbox/issues/2613) - Decrease live search minimum characters to three
-* [#2615](https://github.com/netbox-community/netbox/issues/2615) - Tweak live search widget to use brief format for API requests
-* [#2623](https://github.com/netbox-community/netbox/issues/2623) - Removed the need to pass the model class to the rqworker process for webhooks
-* [#2634](https://github.com/netbox-community/netbox/issues/2634) - Enforce consistent representation of unnamed devices in rack view
-
----
-
-## v2.4.8 (2018-11-20)
-
-### Enhancements
-
-* [#2490](https://github.com/netbox-community/netbox/issues/2490) - Added bulk editing for config contexts
-* [#2557](https://github.com/netbox-community/netbox/issues/2557) - Added object view for tags
-
-### Bug Fixes
-
-* [#2473](https://github.com/netbox-community/netbox/issues/2473) - Fix encoding of long (>127 character) secrets
-* [#2558](https://github.com/netbox-community/netbox/issues/2558) - Filter on all tags when multiple are passed
-* [#2565](https://github.com/netbox-community/netbox/issues/2565) - Improved rendering of Markdown tables
-* [#2575](https://github.com/netbox-community/netbox/issues/2575) - Correct model specified for rack roles table
-* [#2588](https://github.com/netbox-community/netbox/issues/2588) - Catch all exceptions from failed NAPALM API Calls
-* [#2589](https://github.com/netbox-community/netbox/issues/2589) - Virtual machine API serializer should require cluster assignment
-
----
-
-## v2.4.7 (2018-11-06)
-
-### Enhancements
-
-* [#2388](https://github.com/netbox-community/netbox/issues/2388) - Enable filtering of devices/VMs by region
-* [#2427](https://github.com/netbox-community/netbox/issues/2427) - Allow filtering of interfaces by assigned VLAN or VLAN ID
-* [#2512](https://github.com/netbox-community/netbox/issues/2512) - Add device field to inventory item filter form
-
-### Bug Fixes
-
-* [#2502](https://github.com/netbox-community/netbox/issues/2502) - Allow duplicate VIPs inside a uniqueness-enforced VRF
-* [#2514](https://github.com/netbox-community/netbox/issues/2514) - Prevent new connections to already connected interfaces
-* [#2515](https://github.com/netbox-community/netbox/issues/2515) - Only use django-rq admin tmeplate if webhooks are enabled
-* [#2528](https://github.com/netbox-community/netbox/issues/2528) - Enable creating circuit terminations with interface assignment via API
-* [#2549](https://github.com/netbox-community/netbox/issues/2549) - Changed naming of `peer_device` and `peer_interface` on API /dcim/connected-device/ endpoint to use underscores
-
----
-
-## v2.4.6 (2018-10-05)
-
-### Enhancements
-
-* [#2479](https://github.com/netbox-community/netbox/issues/2479) - Add user permissions for creating/modifying API tokens
-* [#2487](https://github.com/netbox-community/netbox/issues/2487) - Return abbreviated API output when passed `?brief=1`
-
-### Bug Fixes
-
-* [#2393](https://github.com/netbox-community/netbox/issues/2393) - Fix Unicode support for CSV import under Python 2
-* [#2483](https://github.com/netbox-community/netbox/issues/2483) - Set max item count of API-populated form fields to MAX_PAGE_SIZE
-* [#2484](https://github.com/netbox-community/netbox/issues/2484) - Local config context not available on the Virtual Machine Edit Form
-* [#2485](https://github.com/netbox-community/netbox/issues/2485) - Fix cancel button when assigning a service to a device/VM
-* [#2491](https://github.com/netbox-community/netbox/issues/2491) - Fix exception when importing devices with invalid device type
-* [#2492](https://github.com/netbox-community/netbox/issues/2492) - Sanitize hostname and port values returned through LLDP
-
----
-
-## v2.4.5 (2018-10-02)
-
-### Enhancements
-
-* [#2392](https://github.com/netbox-community/netbox/issues/2392) - Implemented local context data for devices and virtual machines
-* [#2402](https://github.com/netbox-community/netbox/issues/2402) - Order and format JSON data in form fields
-* [#2432](https://github.com/netbox-community/netbox/issues/2432) - Link remote interface connections to the Interface view
-* [#2438](https://github.com/netbox-community/netbox/issues/2438) - API optimizations for tagged objects
-
-### Bug Fixes
-
-* [#2406](https://github.com/netbox-community/netbox/issues/2406) - Remove hard-coded limit of 1000 objects from API-populated form fields
-* [#2414](https://github.com/netbox-community/netbox/issues/2414) - Tags field missing from device/VM component creation forms
-* [#2442](https://github.com/netbox-community/netbox/issues/2442) - Nullify "next" link in API when limit=0 is passed
-* [#2443](https://github.com/netbox-community/netbox/issues/2443) - Enforce JSON object format when creating config contexts
-* [#2444](https://github.com/netbox-community/netbox/issues/2444) - Improve validation of interface MAC addresses
-* [#2455](https://github.com/netbox-community/netbox/issues/2455) - Ignore unique address enforcement for IPs with a shared/virtual role
-* [#2470](https://github.com/netbox-community/netbox/issues/2470) - Log the creation of device/VM components as object changes
-
----
-
-## v2.4.4 (2018-08-22)
-
-### Enhancements
-
-* [#2168](https://github.com/netbox-community/netbox/issues/2168) - Added Extreme SummitStack interface form factors
-* [#2356](https://github.com/netbox-community/netbox/issues/2356) - Include cluster site as read-only field in VirtualMachine serializer
-* [#2362](https://github.com/netbox-community/netbox/issues/2362) - Implemented custom admin site to properly handle BASE_PATH
-* [#2254](https://github.com/netbox-community/netbox/issues/2254) - Implemented searchability for Rack Groups
-
-### Bug Fixes
-
-* [#2353](https://github.com/netbox-community/netbox/issues/2353) - Handle `DoesNotExist` exception when deleting a device with connected interfaces
-* [#2354](https://github.com/netbox-community/netbox/issues/2354) - Increased maximum MTU for interfaces to 65536 bytes
-* [#2355](https://github.com/netbox-community/netbox/issues/2355) - Added item count to inventory tab on device view
-* [#2368](https://github.com/netbox-community/netbox/issues/2368) - Record change in device changelog when altering cluster assignment
-* [#2369](https://github.com/netbox-community/netbox/issues/2369) - Corrected time zone validation on site API serializer
-* [#2370](https://github.com/netbox-community/netbox/issues/2370) - Redirect to parent device after deleting device bays
-* [#2374](https://github.com/netbox-community/netbox/issues/2374) - Fix toggling display of IP addresses in virtual machine interfaces list
-* [#2378](https://github.com/netbox-community/netbox/issues/2378) - Corrected "edit" link for virtual machine interfaces
-
----
-
-## v2.4.3 (2018-08-09)
-
-### Enhancements
-
-* [#2333](https://github.com/netbox-community/netbox/issues/2333) - Added search filters for ConfigContexts
-
-### Bug Fixes
-
-* [#2334](https://github.com/netbox-community/netbox/issues/2334) - TypeError raised when WritableNestedSerializer receives a non-integer value
-* [#2335](https://github.com/netbox-community/netbox/issues/2335) - API requires group field when creating/updating a rack
-* [#2336](https://github.com/netbox-community/netbox/issues/2336) - Bulk deleting power outlets and console server ports from a device redirects to home page
-* [#2337](https://github.com/netbox-community/netbox/issues/2337) - Attempting to create the next available prefix within a parent assigned to a VRF raises an AssertionError
-* [#2340](https://github.com/netbox-community/netbox/issues/2340) - API requires manufacturer field when creating/updating an inventory item
-* [#2342](https://github.com/netbox-community/netbox/issues/2342) - IntegrityError raised when attempting to assign an invalid IP address as the primary for a VM
-* [#2344](https://github.com/netbox-community/netbox/issues/2344) - AttributeError when assigning VLANs to an interface on a device/VM not assigned to a site
-
----
-
-## v2.4.2 (2018-08-08)
-
-### Bug Fixes
-
-* [#2318](https://github.com/netbox-community/netbox/issues/2318) - ImportError when viewing a report
-* [#2319](https://github.com/netbox-community/netbox/issues/2319) - Extend ChoiceField to properly handle true/false choice keys
-* [#2320](https://github.com/netbox-community/netbox/issues/2320) - TypeError when dispatching a webhook with a secret key configured
-* [#2321](https://github.com/netbox-community/netbox/issues/2321) - Allow explicitly setting a null value on nullable ChoiceFields
-* [#2322](https://github.com/netbox-community/netbox/issues/2322) - Webhooks firing on non-enabled event types
-* [#2323](https://github.com/netbox-community/netbox/issues/2323) - DoesNotExist raised when deleting devices or virtual machines
-* [#2330](https://github.com/netbox-community/netbox/issues/2330) - Incorrect tab link in VRF changelog view
-
----
-
-## v2.4.1 (2018-08-07)
-
-### Bug Fixes
-
-* [#2303](https://github.com/netbox-community/netbox/issues/2303) - Always redirect to parent object when bulk editing/deleting components
-* [#2308](https://github.com/netbox-community/netbox/issues/2308) - Custom fields panel absent from object view in UI
-* [#2310](https://github.com/netbox-community/netbox/issues/2310) - False validation error on certain nested serializers
-* [#2311](https://github.com/netbox-community/netbox/issues/2311) - Redirect to parent after editing interface from device/VM view
-* [#2312](https://github.com/netbox-community/netbox/issues/2312) - Running a report yields a ValueError exception
-* [#2314](https://github.com/netbox-community/netbox/issues/2314) - Serialized representation of object in change log does not include assigned tags
-
----
-
-## v2.4.0 (2018-08-06)
-
-### New Features
-
-#### Webhooks ([#81](https://github.com/netbox-community/netbox/issues/81))
-
-Webhooks enable NetBox to send a representation of an object every time one is created, updated, or deleted. Webhooks are sent from NetBox to external services via HTTP, and can be limited by object type. Services which receive a webhook can act on the data provided by NetBox to automate other tasks.
-
-Special thanks to [John Anderson](https://github.com/lampwins) for doing the heavy lifting for this feature!
-
-#### Tagging ([#132](https://github.com/netbox-community/netbox/issues/132))
-
-Tags are free-form labels which can be assigned to a variety of objects in NetBox. Tags can be used to categorize and filter objects in addition to built-in and custom fields. Objects to which tags apply now include a `tags` field in the API.
-
-#### Contextual Configuration Data ([#1349](https://github.com/netbox-community/netbox/issues/1349))
-
-Sometimes it is desirable to associate arbitrary data with a group of devices to aid in their configuration. (For example, you might want to associate a set of syslog servers for all devices at a particular site.) Context data enables the association of arbitrary data (expressed in JSON format) to devices and virtual machines grouped by region, site, role, platform, and/or tenancy. Context data is arranged hierarchically, so that data with a higher weight can be entered to override more general lower-weight data. Multiple instances of data are automatically merged by NetBox to present a single dictionary for each object.
-
-#### Change Logging ([#1898](https://github.com/netbox-community/netbox/issues/1898))
-
-When an object is created, updated, or deleted, NetBox now automatically records a serialized representation of that object (similar to how it appears in the REST API) as well the event time and user account associated with the change.
-
-### Enhancements
-
-* [#238](https://github.com/netbox-community/netbox/issues/238) - Allow racks with the same name within a site (but in different groups)
-* [#971](https://github.com/netbox-community/netbox/issues/971) - Add a view to show all VLAN IDs available within a group
-* [#1673](https://github.com/netbox-community/netbox/issues/1673) - Added object/list views for services
-* [#1687](https://github.com/netbox-community/netbox/issues/1687) - Enabled custom fields for services
-* [#1739](https://github.com/netbox-community/netbox/issues/1739) - Enabled custom fields for secrets
-* [#1794](https://github.com/netbox-community/netbox/issues/1794) - Improved POST/PATCH representation of nested objects
-* [#2029](https://github.com/netbox-community/netbox/issues/2029) - Added optional NAPALM arguments to Platform model
-* [#2034](https://github.com/netbox-community/netbox/issues/2034) - Include the ID when showing nested interface connections (API change)
-* [#2118](https://github.com/netbox-community/netbox/issues/2118) - Added `latitude` and `longitude` fields to Site for GPS coordinates
-* [#2131](https://github.com/netbox-community/netbox/issues/2131) - Added `created` and `last_updated` fields to DeviceType
-* [#2157](https://github.com/netbox-community/netbox/issues/2157) - Fixed natural ordering of objects when sorted by name
-* [#2225](https://github.com/netbox-community/netbox/issues/2225) - Add "view elevations" button for site rack groups
-
-### Bug Fixes
-
-* [#2272](https://github.com/netbox-community/netbox/issues/2272) - Allow subdevice_role to be null on DeviceTypeSerializer"
-* [#2286](https://github.com/netbox-community/netbox/issues/2286) - Fixed "mark connected" button for PDU outlet connections
-
-### API Changes
-
-* Introduced the `/extras/config-contexts/`, `/extras/object-changes/`, and `/extras/tags/` API endpoints
-* API writes now return a nested representation of related objects (rather than only a numeric ID)
-* The dcim.DeviceType serializer now includes `created` and `last_updated` fields
-* The dcim.Site serializer now includes `latitude` and `longitude` fields
-* The ipam.Service and secrets.Secret serializers now include custom fields
-* The dcim.Platform serializer now includes a free-form (JSON) `napalm_args` field
-
-### Changes Since v2.4-beta1
-
-#### Enhancements
-
-* [#2229](https://github.com/netbox-community/netbox/issues/2229) - Allow mapping of ConfigContexts to tenant groups
-* [#2259](https://github.com/netbox-community/netbox/issues/2259) - Add changelog tab to interface view
-* [#2264](https://github.com/netbox-community/netbox/issues/2264) - Added "map it" link for site GPS coordinates
-
-#### Bug Fixes
-
-* [#2137](https://github.com/netbox-community/netbox/issues/2137) - Fixed JSON serialization of dates
-* [#2258](https://github.com/netbox-community/netbox/issues/2258) - Include changed object type on home page changelog
-* [#2265](https://github.com/netbox-community/netbox/issues/2265) - Include parent regions when filtering applicable ConfigContexts
-* [#2288](https://github.com/netbox-community/netbox/issues/2288) - Fix exception when assigning objects to a ConfigContext via the API
-* [#2296](https://github.com/netbox-community/netbox/issues/2296) - Fix AttributeError when creating a new object with tags assigned
-* [#2300](https://github.com/netbox-community/netbox/issues/2300) - Fix assignment of an interface to an IP address via API PATCH
-* [#2301](https://github.com/netbox-community/netbox/issues/2301) - Fix model validation on assignment of ManyToMany fields via API PATCH
-* [#2305](https://github.com/netbox-community/netbox/issues/2305) - Make VLAN fields optional when creating a VM interface via the API

+ 0 - 367
docs/release-notes/version-2.5.md

@@ -1,367 +0,0 @@
-# NetBox v2.5 Release Notes
-
-## v2.5.13 (2019-05-31)
-
-### Enhancements
-
-* [#2813](https://github.com/netbox-community/netbox/issues/2813) - Add tenant group filters
-* [#3085](https://github.com/netbox-community/netbox/issues/3085) - Catch all exceptions during export template rendering
-* [#3138](https://github.com/netbox-community/netbox/issues/3138) - Add 2.5GE and 5GE interface form factors
-* [#3151](https://github.com/netbox-community/netbox/issues/3151) - Add inventory item count to manufacturers list
-* [#3156](https://github.com/netbox-community/netbox/issues/3156) - Add site link to rack reservations overview
-* [#3183](https://github.com/netbox-community/netbox/issues/3183) - Enable bulk deletion of sites
-* [#3185](https://github.com/netbox-community/netbox/issues/3185) - Improve performance for custom field access within templates
-* [#3186](https://github.com/netbox-community/netbox/issues/3186) - Add interface name filter for IP addresses
-
-### Bug Fixes
-
-* [#3031](https://github.com/netbox-community/netbox/issues/3031) - Fixed form field population of tags with spaces
-* [#3132](https://github.com/netbox-community/netbox/issues/3132) - Circuit termination missing from available cable termination types
-* [#3150](https://github.com/netbox-community/netbox/issues/3150) - Fix formatting of cable length during cable trace
-* [#3184](https://github.com/netbox-community/netbox/issues/3184) - Correctly display color block for white cables
-* [#3190](https://github.com/netbox-community/netbox/issues/3190) - Fix custom field rendering for Jinja2 export templates
-* [#3211](https://github.com/netbox-community/netbox/issues/3211) - Fix error handling when attempting to delete a protected object via API
-* [#3223](https://github.com/netbox-community/netbox/issues/3223) - Fix filtering devices by "has power outlets"
-* [#3227](https://github.com/netbox-community/netbox/issues/3227) - Fix exception when deleting a circuit with a termination(s)
-* [#3228](https://github.com/netbox-community/netbox/issues/3228) - Fixed login link retaining query parameters
-
----
-
-## v2.5.12 (2019-05-01)
-
-### Bug Fixes
-
-* [#3127](https://github.com/netbox-community/netbox/issues/3127) - Fix natural ordering of device components
-
----
-
-2.5.11 (2019-04-29)
-
-### Notes
-
-This release upgrades the Django framework to version 2.2.
-
-### Enhancements
-
-* [#2986](https://github.com/netbox-community/netbox/issues/2986) - Improve natural ordering of device components
-* [#3023](https://github.com/netbox-community/netbox/issues/3023) - Add support for filtering cables by connected device
-* [#3070](https://github.com/netbox-community/netbox/issues/3070) - Add decommissioning status for devices
-
-### Bug Fixes
-
-* [#2621](https://github.com/netbox-community/netbox/issues/2621) - Upgrade Django requirement to 2.2 to fix object deletion issue in the changelog middleware
-* [#3072](https://github.com/netbox-community/netbox/issues/3072) - Preserve multiselect filter values when updating per-page count for list views
-* [#3112](https://github.com/netbox-community/netbox/issues/3112) - Fix ordering of interface connections list by termination B name/device
-* [#3116](https://github.com/netbox-community/netbox/issues/3116) - Fix `tagged_items` count in tags API endpoint
-* [#3118](https://github.com/netbox-community/netbox/issues/3118) - Disable `last_login` update on login when maintenance mode is enabled
-
----
-
-## v2.5.10 (2019-04-08)
-
-### Enhancements
-
-* [#3052](https://github.com/netbox-community/netbox/issues/3052) - Add Jinja2 support for export templates
-
-### Bug Fixes
-
-* [#2937](https://github.com/netbox-community/netbox/issues/2937) - Redirect to list view after editing an object from list view
-* [#3036](https://github.com/netbox-community/netbox/issues/3036) - DCIM interfaces API endpoint should not include VM interfaces
-* [#3039](https://github.com/netbox-community/netbox/issues/3039) - Fix exception when retrieving change object for a component template via API
-* [#3041](https://github.com/netbox-community/netbox/issues/3041) - Fix form widget for bulk cable label update
-* [#3044](https://github.com/netbox-community/netbox/issues/3044) - Ignore site/rack fields when connecting a new cable via device search
-* [#3046](https://github.com/netbox-community/netbox/issues/3046) - Fix exception at reports API endpoint
-* [#3047](https://github.com/netbox-community/netbox/issues/3047) - Fix exception when writing mac address for an interface via API
-
----
-
-## v2.5.9 (2019-04-01)
-
-### Enhancements
-
-* [#2933](https://github.com/netbox-community/netbox/issues/2933) - Add username to outbound webhook requests
-* [#3011](https://github.com/netbox-community/netbox/issues/3011) - Add SSL support for django-rq (requires django-rq v1.3.1+)
-* [#3025](https://github.com/netbox-community/netbox/issues/3025) - Add request ID to outbound webhook requests (for correlating all changes part of a single request)
-
-### Bug Fixes
-
-* [#2207](https://github.com/netbox-community/netbox/issues/2207) - Fixes deterministic ordering of interfaces
-* [#2577](https://github.com/netbox-community/netbox/issues/2577) - Clarification of wording in API regarding filtering
-* [#2924](https://github.com/netbox-community/netbox/issues/2924) - Add interface type for QSFP28 50GE
-* [#2936](https://github.com/netbox-community/netbox/issues/2936) - Fix device role selection showing duplicate first entry
-* [#2998](https://github.com/netbox-community/netbox/issues/2998) - Limit device query to non-racked devices if no rack selected when creating a cable
-* [#3001](https://github.com/netbox-community/netbox/issues/3001) - Fix API representation of ObjectChange `action` and add `changed_object_type`
-* [#3014](https://github.com/netbox-community/netbox/issues/3014) - Fixes VM Role filtering
-* [#3019](https://github.com/netbox-community/netbox/issues/3019) - Fix tag population when running NetBox within a path
-* [#3022](https://github.com/netbox-community/netbox/issues/3022) - Add missing cable termination types to DCIM `_choices` endpoint
-* [#3026](https://github.com/netbox-community/netbox/issues/3026) - Tweak prefix/IP filter forms to filter using VRF ID rather than route distinguisher
-* [#3027](https://github.com/netbox-community/netbox/issues/3027) - Ignore empty local context data when rendering config contexts
-* [#3032](https://github.com/netbox-community/netbox/issues/3032) - Save assigned tags when creating a new secret
-
----
-
-## v2.5.8 (2019-03-11)
-
-### Enhancements
-
-* [#2435](https://github.com/netbox-community/netbox/issues/2435) - Printer friendly CSS
-
-### Bug Fixes
-
-* [#2065](https://github.com/netbox-community/netbox/issues/2065) - Correct documentation for VM interface serializer
-* [#2705](https://github.com/netbox-community/netbox/issues/2705) - Fix endpoint grouping in API docs
-* [#2781](https://github.com/netbox-community/netbox/issues/2781) - Fix filtering of sites/devices/VMs by multiple regions
-* [#2923](https://github.com/netbox-community/netbox/issues/2923) - Provider filter form's site field should be blank by default
-* [#2938](https://github.com/netbox-community/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API
-* [#2939](https://github.com/netbox-community/netbox/issues/2939) - Exclude circuit terminations from API interface connections endpoint
-* [#2940](https://github.com/netbox-community/netbox/issues/2940) - Allow CSV import of prefixes/IPs to VRF without an RD assigned
-* [#2944](https://github.com/netbox-community/netbox/issues/2944) - Record the deletion of an IP address in the changelog of its parent interface (if any)
-* [#2952](https://github.com/netbox-community/netbox/issues/2952) - Added the `slug` field to the Tenant filter for use in the API and search function
-* [#2954](https://github.com/netbox-community/netbox/issues/2954) - Remove trailing slashes to fix root/template paths on Windows
-* [#2961](https://github.com/netbox-community/netbox/issues/2961) - Prevent exception when exporting inventory items belonging to unnamed devices
-* [#2962](https://github.com/netbox-community/netbox/issues/2962) - Increase ExportTemplate `mime_type` field length
-* [#2966](https://github.com/netbox-community/netbox/issues/2966) - Accept `null` cable length_unit via API
-* [#2972](https://github.com/netbox-community/netbox/issues/2972) - Improve ContentTypeField serializer to elegantly handle invalid data
-* [#2976](https://github.com/netbox-community/netbox/issues/2976) - Add delete button to tag view
-* [#2980](https://github.com/netbox-community/netbox/issues/2980) - Improve rendering time for API docs
-* [#2982](https://github.com/netbox-community/netbox/issues/2982) - Correct CSS class assignment on color picker
-* [#2984](https://github.com/netbox-community/netbox/issues/2984) - Fix logging of unlabeled cable ID on cable deletion
-* [#2985](https://github.com/netbox-community/netbox/issues/2985) - Fix pagination page length for rack elevations
-
----
-
-## v2.5.7 (2019-02-21)
-
-### Enhancements
-
-* [#2357](https://github.com/netbox-community/netbox/issues/2357) - Enable filtering of devices by rack face
-* [#2638](https://github.com/netbox-community/netbox/issues/2638) - Add button to copy unlocked secret to clipboard
-* [#2870](https://github.com/netbox-community/netbox/issues/2870) - Add Markdown rendering for provider NOC/admin contact fields
-* [#2878](https://github.com/netbox-community/netbox/issues/2878) - Add cable types for OS1/OS2 singlemode fiber
-* [#2890](https://github.com/netbox-community/netbox/issues/2890) - Add port types for APC fiber
-* [#2898](https://github.com/netbox-community/netbox/issues/2898) - Enable filtering cables list by connection status
-* [#2903](https://github.com/netbox-community/netbox/issues/2903) - Clarify purpose of tags field on interface edit form
-
-### Bug Fixes
-
-* [#2852](https://github.com/netbox-community/netbox/issues/2852) - Allow filtering devices by null rack position
-* [#2884](https://github.com/netbox-community/netbox/issues/2884) - Don't display connect button for wireless interfaces
-* [#2888](https://github.com/netbox-community/netbox/issues/2888) - Correct foreground color of device roles in rack elevations
-* [#2893](https://github.com/netbox-community/netbox/issues/2893) - Remove duplicate display of VRF RD on IP address view
-* [#2895](https://github.com/netbox-community/netbox/issues/2895) - Fix filtering of nullable character fields
-* [#2901](https://github.com/netbox-community/netbox/issues/2901) - Fix ordering regions by site count
-* [#2910](https://github.com/netbox-community/netbox/issues/2910) - Fix config context list and edit forms to use Select2 elements
-* [#2912](https://github.com/netbox-community/netbox/issues/2912) - Cable type in filter form should be blank by default
-* [#2913](https://github.com/netbox-community/netbox/issues/2913) - Fix assigned prefixes link on VRF view
-* [#2914](https://github.com/netbox-community/netbox/issues/2914) - Fix empty connected circuit link on device interfaces list
-* [#2915](https://github.com/netbox-community/netbox/issues/2915) - Fix bulk editing of pass-through ports
-
----
-
-## v2.5.6 (2019-02-13)
-
-### Enhancements
-
-* [#2758](https://github.com/netbox-community/netbox/issues/2758) - Add cable trace button to pass-through ports
-* [#2839](https://github.com/netbox-community/netbox/issues/2839) - Add "110 punch" type for pass-through ports
-* [#2854](https://github.com/netbox-community/netbox/issues/2854) - Enable bulk editing of pass-through ports
-* [#2866](https://github.com/netbox-community/netbox/issues/2866) - Add cellular interface types (GSM/CDMA/LTE)
-
-### Bug Fixes
-
-* [#2841](https://github.com/netbox-community/netbox/issues/2841) - Fix filtering by VRF for prefix and IP address lists
-* [#2844](https://github.com/netbox-community/netbox/issues/2844) - Correct display of far cable end for pass-through ports
-* [#2845](https://github.com/netbox-community/netbox/issues/2845) - Enable filtering of rack unit list by unit ID
-* [#2856](https://github.com/netbox-community/netbox/issues/2856) - Fix navigation links between LAG interfaces and their members on device view
-* [#2857](https://github.com/netbox-community/netbox/issues/2857) - Add `display_name` to DeviceType API serializer; fix DeviceType list for bulk device edit
-* [#2862](https://github.com/netbox-community/netbox/issues/2862) - Follow return URL when connecting a cable
-* [#2864](https://github.com/netbox-community/netbox/issues/2864) - Correct display of VRF name when no RD is assigned
-* [#2877](https://github.com/netbox-community/netbox/issues/2877) - Fixed device role label display on light background color
-* [#2880](https://github.com/netbox-community/netbox/issues/2880) - Sanitize user password if an exception is raised during login
-
----
-
-## v2.5.5 (2019-01-31)
-
-### Enhancements
-
-* [#2805](https://github.com/netbox-community/netbox/issues/2805) - Allow null route distinguisher for VRFs
-* [#2809](https://github.com/netbox-community/netbox/issues/2809) - Remove VRF child prefixes table; link to main prefixes view
-* [#2825](https://github.com/netbox-community/netbox/issues/2825) - Include directly connected device for front/rear ports
-
-### Bug Fixes
-
-* [#2824](https://github.com/netbox-community/netbox/issues/2824) - Fix template exception when viewing rack elevations list
-* [#2833](https://github.com/netbox-community/netbox/issues/2833) - Fix form widget for front port template creation
-* [#2835](https://github.com/netbox-community/netbox/issues/2835) - Fix certain model filters did not support the `q` query param
-* [#2837](https://github.com/netbox-community/netbox/issues/2837) - Fix select2 nullable filter fields add multiple null_option elements when paging
-
----
-
-## v2.5.4 (2019-01-29)
-
-### Enhancements
-
-* [#2516](https://github.com/netbox-community/netbox/issues/2516) - Implemented Select2 for all Model backed selection fields
-* [#2590](https://github.com/netbox-community/netbox/issues/2590) - Implemented the color picker with Select2 to show colors in the background
-* [#2733](https://github.com/netbox-community/netbox/issues/2733) - Enable bulk assignment of MAC addresses to interfaces
-* [#2735](https://github.com/netbox-community/netbox/issues/2735) - Implemented Select2 for all list filter form select elements
-* [#2753](https://github.com/netbox-community/netbox/issues/2753) - Implemented Select2 to replace most all instances of select fields in forms
-* [#2766](https://github.com/netbox-community/netbox/issues/2766) - Extend users admin table to include superuser and active fields
-* [#2782](https://github.com/netbox-community/netbox/issues/2782) - Add `is_pool` field for prefix filtering
-* [#2807](https://github.com/netbox-community/netbox/issues/2807) - Include device site/rack assignment in cable trace view
-* [#2808](https://github.com/netbox-community/netbox/issues/2808) - Loosen version pinning for Django to allow patch releases
-* [#2810](https://github.com/netbox-community/netbox/issues/2810) - Include description fields in interface connections export
-
-### Bug Fixes
-
-* [#2779](https://github.com/netbox-community/netbox/issues/2779) - Include "none" option when filter IP addresses by role
-* [#2783](https://github.com/netbox-community/netbox/issues/2783) - Fix AttributeError exception when attempting to delete region(s)
-* [#2795](https://github.com/netbox-community/netbox/issues/2795) - Fix duplicate display of pagination controls on child prefix/IP tables
-* [#2798](https://github.com/netbox-community/netbox/issues/2798) - Properly URL-encode "map it" link on site view
-* [#2802](https://github.com/netbox-community/netbox/issues/2802) - Better error handling for unsupported NAPALM methods
-* [#2816](https://github.com/netbox-community/netbox/issues/2816) - Handle exception when deleting a device with connected components
-
----
-
-## v2.5.3 (2019-01-11)
-
-### Enhancements
-
-* [#1630](https://github.com/netbox-community/netbox/issues/1630) - Enable bulk editing of prefix/IP mask length
-* [#1870](https://github.com/netbox-community/netbox/issues/1870) - Add per-page toggle to object lists
-* [#1871](https://github.com/netbox-community/netbox/issues/1871) - Enable filtering sites by parent region
-* [#1983](https://github.com/netbox-community/netbox/issues/1983) - Enable regular expressions when bulk renaming device components
-* [#2682](https://github.com/netbox-community/netbox/issues/2682) - Add DAC and AOC cable types
-* [#2693](https://github.com/netbox-community/netbox/issues/2693) - Additional cable colors
-* [#2726](https://github.com/netbox-community/netbox/issues/2726) - Include cables in global search
-
-### Bug Fixes
-
-* [#2742](https://github.com/netbox-community/netbox/issues/2742) - Preserve cluster assignment when editing a device
-* [#2757](https://github.com/netbox-community/netbox/issues/2757) - Always treat first/last IPs within a /31 or /127 as usable
-* [#2762](https://github.com/netbox-community/netbox/issues/2762) - Add missing DCIM field values to API `_choices` endpoint
-* [#2777](https://github.com/netbox-community/netbox/issues/2777) - Fix cable validation to handle duplicate connections on import
-
-
----
-
-## v2.5.2 (2018-12-21)
-
-### Enhancements
-
-* [#2561](https://github.com/netbox-community/netbox/issues/2561) - Add 200G and 400G interface types
-* [#2701](https://github.com/netbox-community/netbox/issues/2701) - Enable filtering of prefixes by exact prefix value
-
-### Bug Fixes
-
-* [#2673](https://github.com/netbox-community/netbox/issues/2673) - Fix exception on LLDP neighbors view for device with a circuit connected
-* [#2691](https://github.com/netbox-community/netbox/issues/2691) - Cable trace should follow circuits
-* [#2698](https://github.com/netbox-community/netbox/issues/2698) - Remove pagination restriction on bulk component creation for devices/VMs
-* [#2704](https://github.com/netbox-community/netbox/issues/2704) - Fix form select widget population on parent with null value
-* [#2707](https://github.com/netbox-community/netbox/issues/2707) - Correct permission evaluation for circuit termination cabling
-* [#2712](https://github.com/netbox-community/netbox/issues/2712) - Preserve list filtering after editing objects in bulk
-* [#2717](https://github.com/netbox-community/netbox/issues/2717) - Fix bulk deletion of tags
-* [#2721](https://github.com/netbox-community/netbox/issues/2721) - Detect loops when tracing front/rear ports
-* [#2723](https://github.com/netbox-community/netbox/issues/2723) - Correct permission evaluation when bulk deleting tags
-* [#2724](https://github.com/netbox-community/netbox/issues/2724) - Limit rear port choices to current device when editing a front port
-
----
-
-## v2.5.1 (2018-12-13)
-
-### Enhancements
-
-* [#2655](https://github.com/netbox-community/netbox/issues/2655) - Add 128GFC Fibrechannel interface type
-* [#2674](https://github.com/netbox-community/netbox/issues/2674) - Enable filtering changelog by object type under web UI
-
-### Bug Fixes
-
-* [#2662](https://github.com/netbox-community/netbox/issues/2662) - Fix ImproperlyConfigured exception when rendering API docs
-* [#2663](https://github.com/netbox-community/netbox/issues/2663) - Prevent duplicate interfaces from appearing under VLAN members view
-* [#2666](https://github.com/netbox-community/netbox/issues/2666) - Correct display of length unit in cables list
-* [#2676](https://github.com/netbox-community/netbox/issues/2676) - Fix exception when passing dictionary value to a ChoiceField
-* [#2678](https://github.com/netbox-community/netbox/issues/2678) - Fix error when viewing webhook in admin UI without write permission
-* [#2680](https://github.com/netbox-community/netbox/issues/2680) - Disallow POST requests to `/dcim/interface-connections/` API endpoint
-* [#2683](https://github.com/netbox-community/netbox/issues/2683) - Fix exception when connecting a cable to a RearPort with no corresponding FrontPort
-* [#2684](https://github.com/netbox-community/netbox/issues/2684) - Fix custom field filtering
-* [#2687](https://github.com/netbox-community/netbox/issues/2687) - Correct naming of before/after filters for changelog entries
-
----
-
-## v2.5.0 (2018-12-10)
-
-### Notes
-
-#### Python 3 Required
-
-As promised, Python 2 support has been completed removed. Python 3.5 or higher is now required to run NetBox. Please see [our Python 3 migration guide](https://docs.netbox.dev/en/stable/installation/migrating-to-python3/) for assistance with upgrading.
-
-#### Removed Deprecated User Activity Log
-
-The UserAction model, which was deprecated by the new change logging feature in NetBox v2.4, has been removed. If you need to archive legacy user activity, do so prior to upgrading to NetBox v2.5, as the database migration will remove all data associated with this model.
-
-#### View Permissions in Django 2.1
-
-Django 2.1 introduces view permissions for object types (not to be confused with object-level permissions). Implementation of [#323](https://github.com/netbox-community/netbox/issues/323) is planned for NetBox v2.6. Users are encourage to begin assigning view permissions as desired in preparation for their eventual enforcement.
-
-#### upgrade.sh No Longer Invokes sudo
-
-The `upgrade.sh` script has been tweaked so that it no longer invokes `sudo` internally. This was done to ensure compatibility when running NetBox inside a Python virtual environment. If you need elevated permissions when upgrading NetBox, call the upgrade script with `sudo upgrade.sh`.
-
-### New Features
-
-#### Patch Panels and Cables ([#20](https://github.com/netbox-community/netbox/issues/20))
-
-NetBox now supports modeling physical cables for console, power, and interface connections. The new pass-through port component type has also been introduced to model patch panels and similar devices.
-
-### Enhancements
-
-* [#450](https://github.com/netbox-community/netbox/issues/450) - Added `outer_width` and `outer_depth` fields to rack model
-* [#867](https://github.com/netbox-community/netbox/issues/867) - Added `description` field to circuit terminations
-* [#1444](https://github.com/netbox-community/netbox/issues/1444) - Added an `asset_tag` field for racks
-* [#1931](https://github.com/netbox-community/netbox/issues/1931) - Added a count of assigned IP addresses to the interface API serializer
-* [#2000](https://github.com/netbox-community/netbox/issues/2000) - Dropped support for Python 2
-* [#2053](https://github.com/netbox-community/netbox/issues/2053) - Introduced the `LOGIN_TIMEOUT` configuration setting
-* [#2057](https://github.com/netbox-community/netbox/issues/2057) - Added description columns to interface connections list
-* [#2104](https://github.com/netbox-community/netbox/issues/2104) - Added a `status` field for racks
-* [#2165](https://github.com/netbox-community/netbox/issues/2165) - Improved natural ordering of Interfaces
-* [#2292](https://github.com/netbox-community/netbox/issues/2292) - Removed the deprecated UserAction model
-* [#2367](https://github.com/netbox-community/netbox/issues/2367) - Removed deprecated RPCClient functionality
-* [#2426](https://github.com/netbox-community/netbox/issues/2426) - Introduced `SESSION_FILE_PATH` configuration setting for authentication without write access to database
-* [#2594](https://github.com/netbox-community/netbox/issues/2594) - `upgrade.sh` no longer invokes sudo
-
-### Changes From v2.5-beta2
-
-* [#2474](https://github.com/netbox-community/netbox/issues/2474) - Add `cabled` and `connection_status` filters for device components
-* [#2616](https://github.com/netbox-community/netbox/issues/2616) - Convert Rack `outer_unit` and Cable `length_unit` to integer-based choice fields
-* [#2622](https://github.com/netbox-community/netbox/issues/2622) - Enable filtering cables by multiple types/colors
-* [#2624](https://github.com/netbox-community/netbox/issues/2624) - Delete associated content type and permissions when removing InterfaceConnection model
-* [#2626](https://github.com/netbox-community/netbox/issues/2626) - Remove extraneous permissions generated from proxy models
-* [#2632](https://github.com/netbox-community/netbox/issues/2632) - Change representation of null values from `0` to `null`
-* [#2639](https://github.com/netbox-community/netbox/issues/2639) - Fix preservation of length/dimensions unit for racks and cables
-* [#2648](https://github.com/netbox-community/netbox/issues/2648) - Include the `connection_status` field in nested represenations of connectable device components
-* [#2649](https://github.com/netbox-community/netbox/issues/2649) - Add `connected_endpoint_type` to connectable device component API representations
-
-### API Changes
-
-* The `/extras/recent-activity/` endpoint (replaced by change logging in v2.4) has been removed
-* The `rpc_client` field has been removed from dcim.Platform (see #2367)
-* Introduced a new API endpoint for cables at `/dcim/cables/`
-* New endpoints for front and rear pass-through ports (and their templates) in parallel with existing device components
-* The fields `interface_connection` on Interface and `interface` on CircuitTermination have been replaced with `connected_endpoint` and `connection_status`
-* A new `cable` field has been added to console, power, and interface components and to circuit terminations
-* New fields for dcim.Rack: `status`, `asset_tag`, `outer_width`, `outer_depth`, `outer_unit`
-* The following boolean filters on dcim.Device and dcim.DeviceType have been renamed:
-    * `is_console_server`: `console_server_ports`
-    * `is_pdu`: `power_outlets`
-    * `is_network_device`: `interfaces`
-* The following new boolean filters have been introduced for dcim.Device and dcim.DeviceType:
-    * `console_ports`
-    * `power_ports`
-    * `pass_through_ports`
-* The field `interface_ordering` has been removed from the DeviceType serializer
-* Added a `description` field to the CircuitTermination serializer
-* Added `ipaddress_count` to InterfaceSerializer to show the count of assigned IP addresses for each interface
-* The `available-prefixes` and `available-ips` IPAM endpoints now return an HTTP 204 response instead of HTTP 400 when no new objects can be created
-* Filtering on null values now uses the string `null` instead of zero

+ 0 - 507
docs/release-notes/version-2.6.md

@@ -1,507 +0,0 @@
-# NetBox v2.6 Release Notes
-
-## v2.6.12 (2020-01-13)
-
-### Enhancements
-
-* [#1982](https://github.com/netbox-community/netbox/issues/1982) - Improved NAPALM method documentation in Swagger (OpenAPI)
-* [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering over the link
-* [#2113](https://github.com/netbox-community/netbox/issues/2113) - Allow NAPALM driver settings to be changed with request headers
-* [#2598](https://github.com/netbox-community/netbox/issues/2598) - Toggle the display of child prefixes/IP addresses
-* [#3009](https://github.com/netbox-community/netbox/issues/3009) - Search by description when assigning IP address to interfaces
-* [#3021](https://github.com/netbox-community/netbox/issues/3021) - Add `tenant` filter field for cables
-* [#3090](https://github.com/netbox-community/netbox/issues/3090) - Enable filtering of interfaces by name on the device view
-* [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations view
-* [#3393](https://github.com/netbox-community/netbox/issues/3393) - Paginate assigned circuits at the provider details view
-* [#3440](https://github.com/netbox-community/netbox/issues/3440) - Add total path length to cable trace
-* [#3491](https://github.com/netbox-community/netbox/issues/3491) - Include content of response on webhook error
-* [#3623](https://github.com/netbox-community/netbox/issues/3623) - Enable word expansion during interface creation
-* [#3668](https://github.com/netbox-community/netbox/issues/3668) - Enable searching by DNS name when assigning IP address
-* [#3851](https://github.com/netbox-community/netbox/issues/3851) - Allow passing initial data to custom script forms
-* [#3891](https://github.com/netbox-community/netbox/issues/3891) - Add `local_context_data` filter for virtual machines
-
-### Bug Fixes
-
-* [#3589](https://github.com/netbox-community/netbox/issues/3589) - Fix validation on tagged VLANs of an interface
-* [#3849](https://github.com/netbox-community/netbox/issues/3849) - Fix ordering of models when dumping data to JSON
-* [#3853](https://github.com/netbox-community/netbox/issues/3853) - Fix device role link on config context view
-* [#3856](https://github.com/netbox-community/netbox/issues/3856) - Allow filtering VM interfaces by multiple MAC addresses
-* [#3857](https://github.com/netbox-community/netbox/issues/3857) - Fix rendering of grouped custom links
-* [#3862](https://github.com/netbox-community/netbox/issues/3862) - Allow filtering device components by multiple device names
-* [#3864](https://github.com/netbox-community/netbox/issues/3864) - Disallow /0 masks for prefixes and IP addresses
-* [#3872](https://github.com/netbox-community/netbox/issues/3872) - Paginate related IPs on the IP address view
-* [#3876](https://github.com/netbox-community/netbox/issues/3876) - Fix minimum/maximum value rendering for site ASN field
-* [#3882](https://github.com/netbox-community/netbox/issues/3882) - Fix filtering of devices by rack group
-* [#3898](https://github.com/netbox-community/netbox/issues/3898) - Fix references to deleted cables without a label
-* [#3905](https://github.com/netbox-community/netbox/issues/3905) - Fix divide-by-zero on power feeds with low power values
-
----
-
-## v2.6.11 (2020-01-03)
-
-### Bug Fixes
-
-* [#3831](https://github.com/netbox-community/netbox/issues/3831) - Fix API-driven filter field rendering (#3812 regression)
-* [#3833](https://github.com/netbox-community/netbox/issues/3833) - Add missing region filters for multiple objects
-
----
-
-## v2.6.10 (2020-01-02)
-
-### Enhancements
-
-* [#2233](https://github.com/netbox-community/netbox/issues/2233) - Add ability to move inventory items between devices
-* [#2892](https://github.com/netbox-community/netbox/issues/2892) - Extend admin UI to allow deleting old report results
-* [#3062](https://github.com/netbox-community/netbox/issues/3062) - Add `assigned_to_interface` filter for IP addresses
-* [#3461](https://github.com/netbox-community/netbox/issues/3461) - Fail gracefully on custom link rendering exception
-* [#3705](https://github.com/netbox-community/netbox/issues/3705) - Provide request context when executing custom scripts
-* [#3762](https://github.com/netbox-community/netbox/issues/3762) - Add date/time picker widgets
-* [#3788](https://github.com/netbox-community/netbox/issues/3788) - Enable partial search for inventory items
-* [#3812](https://github.com/netbox-community/netbox/issues/3812) - Optimize size of pages containing a dynamic selection field
-* [#3827](https://github.com/netbox-community/netbox/issues/3827) - Allow filtering console/power/interface connections by device ID
-
-### Bug Fixes
-
-* [#3106](https://github.com/netbox-community/netbox/issues/3106) - Restrict queryset of chained fields when form validation fails
-* [#3695](https://github.com/netbox-community/netbox/issues/3695) - Include A/Z termination sites for circuits in global search
-* [#3712](https://github.com/netbox-community/netbox/issues/3712) - Scrolling to target (hash) did not account for the header size
-* [#3780](https://github.com/netbox-community/netbox/issues/3780) - Fix AttributeError exception in API docs
-* [#3809](https://github.com/netbox-community/netbox/issues/3809) - Filter platform by manufacturer when editing devices
-* [#3811](https://github.com/netbox-community/netbox/issues/3811) - Fix filtering of racks by group on device list
-* [#3822](https://github.com/netbox-community/netbox/issues/3822) - Fix exception when editing a device bay (regression from #3596)
-
----
-
-## v2.6.9 (2019-12-16)
-
-### Enhancements
-
-* [#3152](https://github.com/netbox-community/netbox/issues/3152) - Include direct link to rack elevations on site view
-* [#3441](https://github.com/netbox-community/netbox/issues/3441) - Move virtual machine results near devices in global search
-* [#3761](https://github.com/netbox-community/netbox/issues/3761) - Added copy button for API tokens
-
-### Bug Fixes
-
-* [#2170](https://github.com/netbox-community/netbox/issues/2170) - Prevent the deletion of a virtual chassis when a cross-member LAG is present
-* [#2358](https://github.com/netbox-community/netbox/issues/2358) - Respect custom field default values when creating objects via the REST API
-* [#3749](https://github.com/netbox-community/netbox/issues/3749) - Fix exception on password change page for local users
-* [#3757](https://github.com/netbox-community/netbox/issues/3757) - Fix unable to assign IP to interface
-
----
-
-## v2.6.8 (2019-12-10)
-
-### Enhancements
-
-* [#3139](https://github.com/netbox-community/netbox/issues/3139) - Disable password change form for LDAP-authenticated users
-* [#3457](https://github.com/netbox-community/netbox/issues/3457) - Display cable colors on device view
-* [#3329](https://github.com/netbox-community/netbox/issues/3329) - Remove obsolete P3P policy header
-* [#3663](https://github.com/netbox-community/netbox/issues/3663) - Add query filters for `created` and `last_updated` fields
-* [#3722](https://github.com/netbox-community/netbox/issues/3722) - Allow the underscore character in IPAddress DNS names
-
-### Bug Fixes
-
-* [#3312](https://github.com/netbox-community/netbox/issues/3312) - Fix validation error when editing power cables in bulk
-* [#3644](https://github.com/netbox-community/netbox/issues/3644) - Fix exception when connecting a cable to a RearPort with no corresponding FrontPort
-* [#3669](https://github.com/netbox-community/netbox/issues/3669) - Include `weight` field in prefix/VLAN role form
-* [#3674](https://github.com/netbox-community/netbox/issues/3674) - Include comments on PowerFeed view
-* [#3679](https://github.com/netbox-community/netbox/issues/3679) - Fix link for assigned ipaddress in interface page
-* [#3709](https://github.com/netbox-community/netbox/issues/3709) - Prevent exception when importing an invalid cable definition
-* [#3720](https://github.com/netbox-community/netbox/issues/3720) - Correctly indicate power feed terminations on cable list
-* [#3724](https://github.com/netbox-community/netbox/issues/3724) - Fix API filtering of interfaces by more than one device name
-* [#3725](https://github.com/netbox-community/netbox/issues/3725) - Enforce client validation for minimum service port number
-
----
-
-## v2.6.7 (2019-11-01)
-
-### Enhancements
-
-* [#3445](https://github.com/netbox-community/netbox/issues/3445) - Add support for additional user defined headers to be added to webhook requests
-* [#3499](https://github.com/netbox-community/netbox/issues/3499) - Add `ca_file_path` to Webhook model to support user supplied CA certificate verification of webhook requests
-* [#3594](https://github.com/netbox-community/netbox/issues/3594) - Add ChoiceVar for custom scripts
-* [#3619](https://github.com/netbox-community/netbox/issues/3619) - Add 400GE OSFP interface type
-* [#3659](https://github.com/netbox-community/netbox/issues/3659) - Add filtering for objects in admin UI
-
-### Bug Fixes
-
-* [#3309](https://github.com/netbox-community/netbox/issues/3309) - Rewrite change logging middleware to resolve sporadic testing failures
-* [#3340](https://github.com/netbox-community/netbox/issues/3340) - Add missing options to connect front ports to console ports
-* [#3357](https://github.com/netbox-community/netbox/issues/3357) - Enable filter sites/devices/VMs by null region
-* [#3460](https://github.com/netbox-community/netbox/issues/3460) - Extend upgrade script to validate Python dependencies
-* [#3596](https://github.com/netbox-community/netbox/issues/3596) - Prevent server error when reassigning a device to a new device bay
-* [#3629](https://github.com/netbox-community/netbox/issues/3629) - Use `get_lldp_neighors_detail` to validation LLDP neighbors
-* [#3635](https://github.com/netbox-community/netbox/issues/3635) - Add missing cache support for the circuits app
-* [#3636](https://github.com/netbox-community/netbox/issues/3636) - Add missing `rack_group` field to PowerFeed CSV export
-* [#3652](https://github.com/netbox-community/netbox/issues/3652) - Limit next/previous rack by assigned rack group
-
----
-
-## v2.6.6 (2019-10-10)
-
-### Notes
-
-* This release includes a migration which automatically updates all existing cables to enable filtering by site/rack (see [#3259](https://github.com/netbox-community/netbox/issues/3259)). This migration may take several minutes to complete on installations with tens of thousands of cables defined.
-
-### Enhancements
-
-* [#1941](https://github.com/netbox-community/netbox/issues/1941) - Add InfiniBand interface types
-* [#3259](https://github.com/netbox-community/netbox/issues/3259) - Add `rack` and `site` filters for cables
-* [#3471](https://github.com/netbox-community/netbox/issues/3471) - Disallow raw HTML in Markdown-rendered fields
-* [#3545](https://github.com/netbox-community/netbox/issues/3545) - Add `MultiObjectVar` for custom scripts
-* [#3563](https://github.com/netbox-community/netbox/issues/3563) - Enable editing of individual DeviceType components
-* [#3580](https://github.com/netbox-community/netbox/issues/3580) - Render text and URL fields as textareas in the custom link form
-* [#3581](https://github.com/netbox-community/netbox/issues/3581) - Introduce `commit_default` custom script attribute to not commit changes by default
-
-### Bug Fixes
-
-* [#3458](https://github.com/netbox-community/netbox/issues/3458) - Prevent primary IP address for a device/VM from being reassigned
-* [#3463](https://github.com/netbox-community/netbox/issues/3463) - Correct CSV headers for exported power feeds
-* [#3474](https://github.com/netbox-community/netbox/issues/3474) - Fix device status page loading when NAPALM call fails
-* [#3571](https://github.com/netbox-community/netbox/issues/3571) - Prevent erroneous redirects when editing tags
-* [#3573](https://github.com/netbox-community/netbox/issues/3573) - Ensure consistent display of changelog retention period
-* [#3574](https://github.com/netbox-community/netbox/issues/3574) - Change `device` to `parent` in interface editing VLAN filtering logic
-* [#3575](https://github.com/netbox-community/netbox/issues/3575) - Restore label for comments field when bulk editing circuits
-* [#3582](https://github.com/netbox-community/netbox/issues/3582) - Enforce view permissions on global search results
-* [#3588](https://github.com/netbox-community/netbox/issues/3588) - Enforce object-form JSON for local context data on devices and VMs
-
----
-
-## v2.6.5 (2019-09-25)
-
-### Enhancements
-
-* [#3297](https://github.com/netbox-community/netbox/issues/3297) - Include reserved units when calculating rack utilization
-* [#3347](https://github.com/netbox-community/netbox/issues/3347) - Extend upgrade script to automatically remove stale content types
-* [#3352](https://github.com/netbox-community/netbox/issues/3352) - Enable filtering changelog API by `changed_object_id`
-* [#3515](https://github.com/netbox-community/netbox/issues/3515) - Enable export templates for inventory items
-* [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations
-* [#3529](https://github.com/netbox-community/netbox/issues/3529) - Enable filtering circuits list by region
-
-### Bug Fixes
-
-* [#3435](https://github.com/netbox-community/netbox/issues/3435) - Change IP/prefix CSV export to reference VRF name instead of RD
-* [#3464](https://github.com/netbox-community/netbox/issues/3464) - Fix foreground text color on color picker fields
-* [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API
-* [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL
-* [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color
-* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs
-* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields
-* [#3543](https://github.com/netbox-community/netbox/issues/3543) - Added inline VLAN editing to virtual machine interfaces
-
----
-
-## v2.6.4 (2019-09-19)
-
-### Enhancements
-
-* [#2160](https://github.com/netbox-community/netbox/issues/2160) - Add bulk editing for interface VLAN assignment
-* [#3027](https://github.com/netbox-community/netbox/issues/3028) - Add `local_context_data` boolean filter for devices
-* [#3318](https://github.com/netbox-community/netbox/issues/3318) - Increase length of platform name and slug to 100 characters
-* [#3341](https://github.com/netbox-community/netbox/issues/3341) - Enable inline VLAN assignment while editing an interface
-* [#3485](https://github.com/netbox-community/netbox/issues/3485) - Enable embedded graphs for devices
-* [#3510](https://github.com/netbox-community/netbox/issues/3510) - Add minimum/maximum prefix length enforcement for `IPNetworkVar`
-
-### Bug Fixes
-
-* [#3489](https://github.com/netbox-community/netbox/issues/3489) - Prevent exception triggered by webhook upon object deletion
-* [#3501](https://github.com/netbox-community/netbox/issues/3501) - Fix rendering of checkboxes on custom script forms
-* [#3511](https://github.com/netbox-community/netbox/issues/3511) - Correct API URL for nested device bays
-* [#3513](https://github.com/netbox-community/netbox/issues/3513) - Fix assignment of tags when creating front/rear ports
-* [#3514](https://github.com/netbox-community/netbox/issues/3514) - Label TextVar fields when rendering custom script forms
-
----
-
-## v2.6.3 (2019-09-04)
-
-### New Features
-
-#### Custom Scripts ([#3415](https://github.com/netbox-community/netbox/issues/3415))
-
-Custom scripts allow for the execution of arbitrary code via the NetBox UI. They can be used to automatically create, manipulate, or clean up objects or perform other tasks within NetBox. Scripts are defined as Python files which contain one or more subclasses of `extras.scripts.Script`. Variable fields can be defined within scripts, which render as form fields within the web UI to prompt the user for input data. Scripts are executed and information is logged via the web UI. Please see [the docs](https://docs.netbox.dev/en/stable/customization/custom-scripts/) for more detail.
-
-Note: There are currently no API endpoints for this feature. These are planned for the upcoming v2.7 release.
-
-### Enhancements
-
-* [#3386](https://github.com/netbox-community/netbox/issues/3386) - Add `mac_address` filter for virtual machines
-* [#3391](https://github.com/netbox-community/netbox/issues/3391) - Update Bootstrap CSS to v3.4.1
-* [#3405](https://github.com/netbox-community/netbox/issues/3405) - Fix population of power port/outlet details on device creation
-* [#3422](https://github.com/netbox-community/netbox/issues/3422) - Prevent navigation menu from overlapping page content
-* [#3430](https://github.com/netbox-community/netbox/issues/3430) - Linkify platform field on device view
-* [#3454](https://github.com/netbox-community/netbox/issues/3454) - Enable filtering circuits by region
-* [#3456](https://github.com/netbox-community/netbox/issues/3456) - Enable bulk editing of tag color
-
-### Bug Fixes
-
-* [#3392](https://github.com/netbox-community/netbox/issues/3392) - Add database index for ObjectChange time
-* [#3420](https://github.com/netbox-community/netbox/issues/3420) - Serial number filter for racks, devices, and inventory items is now case-insensitive
-* [#3428](https://github.com/netbox-community/netbox/issues/3428) - Fixed cache invalidation issues ([#3300](https://github.com/netbox-community/netbox/issues/3300), [#3363](https://github.com/netbox-community/netbox/issues/3363), [#3379](https://github.com/netbox-community/netbox/issues/3379), [#3382](https://github.com/netbox-community/netbox/issues/3382)) by switching to `prefetch_related()` instead of `select_related()` and removing use of `update()`
-* [#3421](https://github.com/netbox-community/netbox/issues/3421) - Fix exception when ordering power connections list by PDU
-* [#3424](https://github.com/netbox-community/netbox/issues/3424) - Fix tag coloring for non-linked tags
-* [#3426](https://github.com/netbox-community/netbox/issues/3426) - Improve API error handling for ChoiceFields
-
----
-
-## v2.6.2 (2019-08-02)
-
-### Enhancements
-
-* [#984](https://github.com/netbox-community/netbox/issues/984) - Allow ordering circuits by A/Z side
-* [#3307](https://github.com/netbox-community/netbox/issues/3307) - Add power panels count to home page
-* [#3314](https://github.com/netbox-community/netbox/issues/3314) - Paginate object changelog entries
-* [#3367](https://github.com/netbox-community/netbox/issues/3367) - Add BNC port type and coaxial cable type
-* [#3368](https://github.com/netbox-community/netbox/issues/3368) - Indicate indefinite changelog retention when applicable
-* [#3370](https://github.com/netbox-community/netbox/issues/3370) - Add filter class to VirtualChassis API
-
-### Bug Fixes
-
-* [#3018](https://github.com/netbox-community/netbox/issues/3018) - Components connected via a cable must have an equal number of positions
-* [#3289](https://github.com/netbox-community/netbox/issues/3289) - Prevent position from being nullified when moving a device to a new rack
-* [#3293](https://github.com/netbox-community/netbox/issues/3293) - Enable filtering device components by multiple device IDs
-* [#3315](https://github.com/netbox-community/netbox/issues/3315) - Enable filtering devices/interfaces by multiple MAC addresses
-* [#3317](https://github.com/netbox-community/netbox/issues/3317) - Fix permissions for ConfigContextBulkDeleteView
-* [#3323](https://github.com/netbox-community/netbox/issues/3323) - Fix permission evaluation for interface connections view
-* [#3342](https://github.com/netbox-community/netbox/issues/3342) - Fix cluster delete button
-* [#3384](https://github.com/netbox-community/netbox/issues/3384) - Maximum and allocated draw fields should be included on power port template creation form
-* [#3385](https://github.com/netbox-community/netbox/issues/3385) - Fix power panels list when bulk editing power feeds
-
----
-
-## v2.6.1 (2019-06-25)
-
-### Enhancements
-
-* [#3154](https://github.com/netbox-community/netbox/issues/3154) - Add `virtual_chassis_member` device filter
-* [#3277](https://github.com/netbox-community/netbox/issues/3277) - Add cable trace buttons for console and power ports
-* [#3281](https://github.com/netbox-community/netbox/issues/3281) - Hide custom links which render as empty text
-
-### Bug Fixes
-
-* [#3229](https://github.com/netbox-community/netbox/issues/3229) - Limit rack group selection by parent site on racks list
-* [#3269](https://github.com/netbox-community/netbox/issues/3269) - Raise validation error when specifying non-existent cable terminations
-* [#3275](https://github.com/netbox-community/netbox/issues/3275) - Fix error when adding power outlets to a device type
-* [#3279](https://github.com/netbox-community/netbox/issues/3279) - Reset the PostgreSQL sequence for Tag and TaggedItem IDs
-* [#3283](https://github.com/netbox-community/netbox/issues/3283) - Fix rack group assignment on PowerFeed CSV import
-* [#3290](https://github.com/netbox-community/netbox/issues/3290) - Fix server error when viewing cascaded PDUs
-* [#3292](https://github.com/netbox-community/netbox/issues/3292) - Ignore empty URL query parameters
-
----
-
-## v2.6.0 (2019-06-20)
-
-### New Features
-
-#### Power Panels and Feeds ([#54](https://github.com/netbox-community/netbox/issues/54))
-
-NetBox now supports power circuit modeling via two new models: power panels and power feeds. Power feeds are terminated
-to power panels and are optionally associated with individual racks. Each power feed defines a supply type (AC/DC),
-amperage, voltage, and phase. A power port can be connected directly to a power feed, but a power feed may have only one
-power port connected to it.
-
-Additionally, the power port model, which represents a device's power input, has been extended to include fields
-denoting maximum and allocated draw, in volt-amperes. This allows a device (e.g. a PDU) to calculate its total load
-compared to its connected power feed.
-
-#### Caching ([#2647](https://github.com/netbox-community/netbox/issues/2647))
-
-To improve performance, NetBox now supports caching for most object and list views. Caching is implemented using Redis,
-which is now a required dependency. (Previously, Redis was required only if webhooks were enabled.)
-
-A new configuration parameter is available to control the cache timeout:
-
-```
-## Cache timeout (in seconds)
-CACHE_TIMEOUT = 900
-```
-
-#### View Permissions ([#323](https://github.com/netbox-community/netbox/issues/323))
-
-Django 2.1 introduced the ability to enforce view-only permissions for different object types. NetBox now enforces
-these by default. You can grant view permission to a user or group by assigning the "can view" permission for the
-desired object(s).
-
-To exempt certain object types from the enforcement of view permissions, so that any user (including anonymous users)
-can view them, add them to the new `EXEMPT_VIEW_PERMISSIONS` setting in `configuration.py`:
-
-```
-EXEMPT_VIEW_PERMISSIONS = [
-    'dcim.site',
-    'ipam.prefix',
-]
-```
-
-To exclude _all_ objects, effectively disabling view permissions and restoring pre-v2.6 behavior, set:
-
-```
-EXEMPT_VIEW_PERMISSIONS = ['*']
-```
-
-#### Custom Links ([#969](https://github.com/netbox-community/netbox/issues/969))
-
-Custom links are created under the admin UI and will be displayed on each object of the selected type. Link text and
-URLs can be formed from Jinja2 template code, with the viewed object passed as context data. For example, to link to an
-external NMS from the device view, you might create a custom link with the following URL:
-
-```
-https://nms.example.com/nodes/?name={{ obj.name }}
-```
-
-Custom links appear as buttons at the top of the object view. Grouped links will render as a dropdown menu beneath a
-single button.
-
-#### Prometheus Metrics ([#3104](https://github.com/netbox-community/netbox/issues/3104))
-
-NetBox now supports exposing native Prometheus metrics from the application. [Prometheus](https://prometheus.io/) is a
-popular time series metric platform used for monitoring. Metric exposition can be toggled with the `METRICS_ENABLED`
-configuration setting; it is not enabled by default. NetBox exposes metrics at the `/metrics` HTTP endpoint, e.g.
-`https://netbox.local/metrics`.
-
-NetBox makes use of the [django-prometheus](https://github.com/korfuri/django-prometheus) library to export a number of
-different types of metrics, including:
-
-* Per model insert, update, and delete counters
-* Per view request counters
-* Per view request latency histograms
-* Request body size histograms
-* Response body size histograms
-* Response code counters
-* Database connection, execution, and error counters
-* Cache hit, miss, and invalidation counters
-* Django middleware latency histograms
-* Other Django related metadata metrics
-
-For the exhaustive list of exposed metrics, visit the `/metrics` endpoint on your NetBox instance. See the documentation
-for more details on using Prometheus metrics in NetBox.
-
-### Changes
-
-#### New Dependency: Redis
-
-[Redis](https://redis.io/) is an in-memory data store similar to memcached. While Redis has been an optional component
-of NetBox since the introduction of webhooks in version 2.4, it is now required to support NetBox's new caching
-functionality (as well as other planned features). Redis can be installed via your platform's package manager: for
-example, `sudo apt-get install redis-server` on Ubuntu or `sudo yum install redis` on CentOS.
-
-The Redis database is configured using a configuration setting similar to `DATABASE` in `configuration.py`:
-
-```
-REDIS = {
-    'HOST': 'localhost',
-    'PORT': 6379,
-    'PASSWORD': '',
-    'DATABASE': 0,
-    'CACHE_DATABASE': 1,
-    'DEFAULT_TIMEOUT': 300,
-    'SSL': False,
-}
-```
-
-Note that if you were using these settings in a prior release with webhooks, the `DATABASE` setting remains the same but
-an additional `CACHE_DATABASE` setting has been added with a default value of 1 to support the caching backend. The
-`DATABASE` setting will be renamed in a future release of NetBox to better relay the meaning of the setting. It is
-highly recommended to keep the webhook and cache databases seperate. Using the same database number for both may result
-in webhook processing data being lost during cache flushing events.
-
-#### API Support for Specifying Related Objects by Attributes([#3077](https://github.com/netbox-community/netbox/issues/3077))
-
-Previously, specifying a related object in an API request required knowing the primary key (integer ID) of that object.
-For example, when creating a new device, its rack would be specified as an integer:
-
-```
-{
-    "name": "MyNewDevice",
-    "rack": 123,
-    ...
-}
-```
-
-The NetBox API now also supports referencing related objects by a set of sufficiently unique attrbiutes. For example, a
-rack can be identified by its name and parent site:
-
-```
-{
-    "name": "MyNewDevice",
-    "rack": {
-        "site": {
-            "name": "Equinix DC6"
-        },
-        "name": "R204"
-    },
-    ...
-}
-```
-
-There is no limit to the depth of nested references. Note that if the provided parameters do not return exactly one
-object, a validation error is raised.
-
-#### API Device/VM Config Context Included by Default ([#2350](https://github.com/netbox-community/netbox/issues/2350))
-
-The rendered config context for devices and VMs is now included by default in all API results (list and detail views).
-Previously, the rendered config context was available only in the detail view for individual objects. Users with large
-amounts of context data may observe a performance drop when returning multiple objects. To combat this, in cases where
-the rendered config context is not needed, the query parameter `?exclude=config_context` may be appended to the request
-URL to exclude the config context data from the API response.
-
-#### Changes to Tag Permissions
-
-NetBox now makes use of its own `Tag` model instead of the stock model which ships with django-taggit. This new model
-lives in the `extras` app and thus any permissions that you may have configured using "Taggit | Tag" should be changed
-to now use "Extras | Tag." Also note that the admin interface for tags has been removed as it was redundant to the
-functionality provided by the front end UI.
-
-#### CORS_ORIGIN_WHITELIST Requires URI Scheme
-
-If you have the `CORS_ORIGIN_WHITELIST` configuration parameter defined, note that each origin must now incldue a URI
-scheme. This change was introuced in django-cors-headers 3.0.
-
-### Enhancements
-
-* [#166](https://github.com/netbox-community/netbox/issues/166) - Add `dns_name` field to IPAddress
-* [#524](https://github.com/netbox-community/netbox/issues/524) - Added power utilization graphs to power feeds, devices, and racks
-* [#1792](https://github.com/netbox-community/netbox/issues/1792) - Add CustomFieldChoices API endpoint at `/api/extras/_custom_field_choices/`
-* [#1863](https://github.com/netbox-community/netbox/issues/1863) - Add child object counts to API representation of organizational objects
-* [#2324](https://github.com/netbox-community/netbox/issues/2324) - Add `color` field for tags
-* [#2643](https://github.com/netbox-community/netbox/issues/2643) - Add `description` field to console/power components and device bays
-* [#2791](https://github.com/netbox-community/netbox/issues/2791) - Add `comments` field for tags
-* [#2920](https://github.com/netbox-community/netbox/issues/2920) - Rename Interface `form_factor` to `type` (backward-compatible until v2.7)
-* [#2926](https://github.com/netbox-community/netbox/issues/2926) - Add change logging to the Tag model
-* [#3038](https://github.com/netbox-community/netbox/issues/3038) - OR logic now used when multiple values of a query filter are passed
-* [#3264](https://github.com/netbox-community/netbox/issues/3264) - Annotate changelog retention time on UI
-
-### Bug Fixes
-
-* [#2968](https://github.com/netbox-community/netbox/issues/2968) - Correct API documentation for SerializerMethodFields
-* [#3176](https://github.com/netbox-community/netbox/issues/3176) - Add cable trace button for console server ports and power outlets
-* [#3231](https://github.com/netbox-community/netbox/issues/3231) - Fixed cosmetic error indicating a missing schema migration
-* [#3239](https://github.com/netbox-community/netbox/issues/3239) - Corrected count of tags reported via API
-
-### Bug Fixes From v2.6-beta1
-
-* [#3123](https://github.com/netbox-community/netbox/issues/3123) - Exempt `/metrics` view from authentication
-* [#3125](https://github.com/netbox-community/netbox/issues/3125) - Fix exception when viewing PDUs
-* [#3126](https://github.com/netbox-community/netbox/issues/3126) - Incorrect calculation of PowerFeed available power
-* [#3130](https://github.com/netbox-community/netbox/issues/3130) - Fix exception when creating a new power outlet
-* [#3136](https://github.com/netbox-community/netbox/issues/3136) - Add power draw fields to power port creation form
-* [#3137](https://github.com/netbox-community/netbox/issues/3137) - Add `power_port` and `feed_leg` fields to power outlet creation form
-* [#3140](https://github.com/netbox-community/netbox/issues/3140) - Add bulk edit capability for power outlets and console server ports
-* [#3204](https://github.com/netbox-community/netbox/issues/3204) - Fix interface filtering when connecting cables
-* [#3207](https://github.com/netbox-community/netbox/issues/3207) - Fix link for connecting interface to rear port
-* [#3258](https://github.com/netbox-community/netbox/issues/3258) - Exception raised when creating/viewing a circuit with a non-connected termination
-
-### API Changes
-
-* New API endpoints for power modeling: `/api/dcim/power-panels/` and `/api/dcim/power-feeds/`
-* New API endpoint for custom field choices: `/api/extras/_custom_field_choices/`
-* ForeignKey fields now accept either the related object PK or a dictionary of attributes describing the related object.
-* Organizational objects now include child object counts. For example, the Role serializer includes `prefix_count` and `vlan_count`.
-* The `id__in` filter is now deprecated and will be removed in v2.7. (Begin using the `?id=1&id=2` format instead.)
-* Added a `description` field for all device components.
-* dcim.Device: The devices list endpoint now includes rendered context data.
-* dcim.DeviceType: `instance_count` has been renamed to `device_count`.
-* dcim.Interface: `form_factor` has been renamed to `type`. Backward compatibility for `form_factor` will be maintained until NetBox v2.7.
-* dcim.Interface: The `type` filter has been renamed to `kind`.
-* dcim.Site: The `count_*` read-only fields have been renamed to `*_count` for consistency with other objects.
-* dcim.Site: Added the `virtualmachine_count` read-only field.
-* extras.Tag: Added `color` and `comments` fields to the Tag serializer.
-* virtualization.VirtualMachine: The virtual machines list endpoint now includes rendered context data.

+ 0 - 573
docs/release-notes/version-2.7.md

@@ -1,573 +0,0 @@
-# NetBox v2.7 Release Notes
-
-## v2.7.12 (2020-04-08)
-
-### Enhancements
-
-* [#3676](https://github.com/netbox-community/netbox/issues/3676) - Reference VRF by name rather than RD during IP/prefix import
-* [#4147](https://github.com/netbox-community/netbox/issues/4147) - Use absolute URLs in rack elevation SVG renderings
-* [#4448](https://github.com/netbox-community/netbox/issues/4448) - Allow connecting cables between two circuit terminations
-* [#4460](https://github.com/netbox-community/netbox/issues/4460) - Add the `webhook_receiver` management command to assist in troubleshooting outgoing webhooks
-
-### Bug Fixes
-
-* [#4395](https://github.com/netbox-community/netbox/issues/4395) - Fix typing of count_ipaddresses on interface serializer
-* [#4418](https://github.com/netbox-community/netbox/issues/4418) - Fail cleanly when trying to import multiple device types simultaneously
-* [#4438](https://github.com/netbox-community/netbox/issues/4438) - Fix exception when disconnecting a cable from a power feed
-* [#4439](https://github.com/netbox-community/netbox/issues/4439) - Tweak display of unset custom integer fields
-* [#4449](https://github.com/netbox-community/netbox/issues/4449) - Fix reservation edit/delete button URLs on rack view
-
----
-
-## v2.7.11 (2020-03-27)
-
-### Enhancements
-
-* [#738](https://github.com/netbox-community/netbox/issues/738) - Add ability to automatically check for new releases (must be enabled by setting `RELEASE_CHECK_URL`)
-* [#4255](https://github.com/netbox-community/netbox/issues/4255) - Custom script object variables now utilize dynamic form widgets
-* [#4309](https://github.com/netbox-community/netbox/issues/4309) - Add descriptive tooltip to custom fields on object views
-* [#4369](https://github.com/netbox-community/netbox/issues/4369) - Add a dedicated view for rack reservations
-* [#4380](https://github.com/netbox-community/netbox/issues/4380) - Enable webhooks for rack reservations
-* [#4381](https://github.com/netbox-community/netbox/issues/4381) - Enable export templates for rack reservations
-* [#4382](https://github.com/netbox-community/netbox/issues/4382) - Enable custom links for rack reservations
-* [#4386](https://github.com/netbox-community/netbox/issues/4386) - Update admin links for Django RQ to reflect multiple queues
-* [#4389](https://github.com/netbox-community/netbox/issues/4389) - Add a bulk edit view for device bays
-* [#4404](https://github.com/netbox-community/netbox/issues/4404) - Add cable trace button for circuit terminations
-
-### Bug Fixes
-
-* [#2769](https://github.com/netbox-community/netbox/issues/2769) - Improve `prefix_length` validation on available-prefixes API
-* [#3193](https://github.com/netbox-community/netbox/issues/3193) - Fix cable tracing across multiple rear ports
-* [#4340](https://github.com/netbox-community/netbox/issues/4340) - Enforce unique constraints for device and virtual machine names in the API
-* [#4343](https://github.com/netbox-community/netbox/issues/4343) - Fix Markdown support for tables
-* [#4365](https://github.com/netbox-community/netbox/issues/4365) - Fix exception raised on IP address bulk add view
-* [#4415](https://github.com/netbox-community/netbox/issues/4415) - Fix duplicate name validation on device model
-
----
-
-## v2.7.10 (2020-03-10)
-
-**Note:** If your deployment requires any non-core Python packages (such as `napalm`, `django-storages`, or `django-auth-ldap`), list them in a file named `local_requirements.txt` in the NetBox root directory (alongside `requirements.txt`). This will ensure they are detected and re-installed by the upgrade script when the Python virtual environment is rebuilt.
-
-### Enhancements
-
-* [#4217](https://github.com/netbox-community/netbox/issues/4217) - Embed model documentation within web UI
-* [#4323](https://github.com/netbox-community/netbox/issues/4323) - Add bulk edit view for power panels
-* [#4324](https://github.com/netbox-community/netbox/issues/4324) - Add CSV import view for services
-* [#4325](https://github.com/netbox-community/netbox/issues/4324) - Add CSV import view for rack reservations
-* [#4332](https://github.com/netbox-community/netbox/issues/4332) - Redirect to a user-friendly error page when CSS/JS resources fail to load
-
-### Bug Fixes
-
-* [#4326](https://github.com/netbox-community/netbox/issues/4326) - Exclude Python modules without Script classes from scripts list
-* [#4337](https://github.com/netbox-community/netbox/issues/4337) - Allow bulk editing/deletion of all device components matching a query
-* [#4338](https://github.com/netbox-community/netbox/issues/4338) - Catch `AddrFormatError` exception when filtering aggregates/prefixes by an invalid prefix
-
----
-
-## v2.7.9 (2020-03-06)
-
-**Note:** This release will deploy a Python virtual environment on upgrade in the `venv/` directory. This will require modifying the paths to your Python and gunicorn executables in the systemd service files. For more detail, please see the [upgrade instructions](https://docs.netbox.dev/en/stable/installation/upgrading/).
-
-### Enhancements
-
-* [#3949](https://github.com/netbox-community/netbox/issues/3949) - Revised the installation docs and upgrade script to employ a Python virtual environment
-* [#4062](https://github.com/netbox-community/netbox/issues/4062) - Enumerate ChoiceField type and value in API
-* [#4119](https://github.com/netbox-community/netbox/issues/4119) - Extend upgrade script to clear expired user sessions
-* [#4121](https://github.com/netbox-community/netbox/issues/4121) - Add dynamic lookup expressions for all filters
-* [#4218](https://github.com/netbox-community/netbox/issues/4218) - Allow negative voltage for DC power feeds
-* [#4281](https://github.com/netbox-community/netbox/issues/4281) - Allow filtering device component list views by type
-* [#4284](https://github.com/netbox-community/netbox/issues/4284) - Add MRJ21 port and cable types
-* [#4290](https://github.com/netbox-community/netbox/issues/4290) - Include device name in tooltip on rack elevations
-* [#4305](https://github.com/netbox-community/netbox/issues/4305) - Add 10-inch option for rack width
-
-### Bug Fixes
-
-* [#4274](https://github.com/netbox-community/netbox/issues/4274) - Fix incorrect schema definition of `int` type choicefields
-* [#4277](https://github.com/netbox-community/netbox/issues/4277) - Fix filtering of clusters by tenant
-* [#4282](https://github.com/netbox-community/netbox/issues/4282) - Fix label on export button for device types
-* [#4285](https://github.com/netbox-community/netbox/issues/4285) - Include A/Z termination sites in provider circuits table
-* [#4295](https://github.com/netbox-community/netbox/issues/4295) - Fix assignment of parent LAG during interface bulk edit
-* [#4298](https://github.com/netbox-community/netbox/issues/4298) - Fix bulk creation of objects with custom fields via REST API
-* [#4300](https://github.com/netbox-community/netbox/issues/4300) - Pass "commit" argument when executing scripts via REST API
-* [#4301](https://github.com/netbox-community/netbox/issues/4301) - Fix exception when deleting device type with components
-* [#4306](https://github.com/netbox-community/netbox/issues/4306) - Fix toggling of device images for all racks in elevations view
-
----
-
-## v2.7.8 (2020-02-25)
-
-### Enhancements
-
-* [#3145](https://github.com/netbox-community/netbox/issues/3145) - Add a "decommissioning" cable status
-* [#4173](https://github.com/netbox-community/netbox/issues/4173) - Return graceful error message when webhook queuing fails
-* [#4227](https://github.com/netbox-community/netbox/issues/4227) - Omit internal fields from the change log data
-* [#4237](https://github.com/netbox-community/netbox/issues/4237) - Support Jinja2 templating for webhook payload and headers
-* [#4262](https://github.com/netbox-community/netbox/issues/4262) - Extend custom scripts to pass the `commit` value via `run()`
-* [#4267](https://github.com/netbox-community/netbox/issues/4267) - Denote rack role on rack elevations list
-
-### Bug Fixes
-
-* [#4221](https://github.com/netbox-community/netbox/issues/4221) - Fix exception when deleting a device with interface connections when an interfaces webhook is defined
-* [#4222](https://github.com/netbox-community/netbox/issues/4222) - Escape double quotes on encapsulated values during CSV export
-* [#4224](https://github.com/netbox-community/netbox/issues/4224) - Fix display of rear device image if front image is not defined
-* [#4228](https://github.com/netbox-community/netbox/issues/4228) - Improve fit of device images in rack elevations
-* [#4230](https://github.com/netbox-community/netbox/issues/4230) - Fix rack units filtering on elevation endpoint
-* [#4232](https://github.com/netbox-community/netbox/issues/4232) - Enforce consistent background striping in rack elevations
-* [#4235](https://github.com/netbox-community/netbox/issues/4235) - Fix API representation of `content_type` for export templates
-* [#4239](https://github.com/netbox-community/netbox/issues/4239) - Fix exception when selecting all filtered objects during bulk edit
-* [#4240](https://github.com/netbox-community/netbox/issues/4240) - Fix exception when filtering foreign keys by NULL
-* [#4241](https://github.com/netbox-community/netbox/issues/4241) - Correct IP address hyperlinks on interface view
-* [#4246](https://github.com/netbox-community/netbox/issues/4246) - Fix duplication of field attributes when multiple IPNetworkVars are present in a script
-* [#4252](https://github.com/netbox-community/netbox/issues/4252) - Fix power port assignment for power outlet templates created via REST API
-* [#4272](https://github.com/netbox-community/netbox/issues/4272) - Interface type should be required by API serializer
-
----
-
-## v2.7.7 (2020-02-20)
-
-**Note:** This release fixes a bug affecting the natural ordering of interfaces. If any interfaces appear unordered in
-NetBox, run the following management command to recalculate their naturalized values after upgrading:
-
-```
-python3 manage.py renaturalize dcim.Interface
-```
-
-### Enhancements
-
-* [#1529](https://github.com/netbox-community/netbox/issues/1529) - Enable display of device images in rack elevations
-* [#2511](https://github.com/netbox-community/netbox/issues/2511) - Compare object change to the previous change
-* [#3810](https://github.com/netbox-community/netbox/issues/3810) - Preserve slug value when editing existing objects
-* [#3840](https://github.com/netbox-community/netbox/issues/3840) - Enhance search function when selecting VLANs for interface assignment
-* [#4170](https://github.com/netbox-community/netbox/issues/4170) - Improve color contrast in rack elevation drawings
-* [#4206](https://github.com/netbox-community/netbox/issues/4206) - Add RJ-11 console port type
-* [#4209](https://github.com/netbox-community/netbox/issues/4209) - Enable filtering interfaces list view by enabled
-
-### Bug Fixes
-
-* [#2519](https://github.com/netbox-community/netbox/issues/2519) - Avoid race condition when provisioning "next available" IPs/prefixes via the API
-* [#3967](https://github.com/netbox-community/netbox/issues/3967) - Fix missing migration for interface templates of type "other"
-* [#4168](https://github.com/netbox-community/netbox/issues/4168) - Role is not required when creating a virtual machine
-* [#4175](https://github.com/netbox-community/netbox/issues/4175) - Fix potential exception when bulk editing objects from a filtered list
-* [#4179](https://github.com/netbox-community/netbox/issues/4179) - Site is required when creating a rack group or power panel
-* [#4183](https://github.com/netbox-community/netbox/issues/4183) - Fix representation of NaturalOrderingField values in change log
-* [#4194](https://github.com/netbox-community/netbox/issues/4194) - Role field should not be required when searching/filtering secrets
-* [#4196](https://github.com/netbox-community/netbox/issues/4196) - Fix exception when viewing LLDP neighbors page
-* [#4202](https://github.com/netbox-community/netbox/issues/4202) - Prevent reassignment to master device when bulk editing VC member interfaces
-* [#4204](https://github.com/netbox-community/netbox/issues/4204) - Fix assignment of mask length when bulk editing prefixes
-* [#4211](https://github.com/netbox-community/netbox/issues/4211) - Include trailing text when naturalizing interface names
-* [#4213](https://github.com/netbox-community/netbox/issues/4213) - Restore display of tags and custom fields on power feed view
-
----
-
-## v2.7.6 (2020-02-13)
-
-### Bug Fixes
-
-* [#4166](https://github.com/netbox-community/netbox/issues/4166) - Fix schema migrations to enforce maximum character length for naturalized fields
-
----
-
-## v2.7.5 (2020-02-13)
-
-**Note:** This release includes several database schema migrations that calculate and store copies of names for certain objects to improve natural ordering performance (see [#3799](https://github.com/netbox-community/netbox/issues/3799)). These migrations may take a few minutes to run if you have a very large number of objects defined in NetBox.
-
-### Enhancements
-
-* [#3766](https://github.com/netbox-community/netbox/issues/3766) - Allow custom script authors to specify the form widget for each variable
-* [#3799](https://github.com/netbox-community/netbox/issues/3799) - Greatly improve performance when ordering device components
-* [#3984](https://github.com/netbox-community/netbox/issues/3984) - Add support for Redis Sentinel
-* [#3986](https://github.com/netbox-community/netbox/issues/3986) - Include position numbers in SVG image when rendering rack elevations
-* [#4093](https://github.com/netbox-community/netbox/issues/4093) - Add more status choices for virtual machines
-* [#4100](https://github.com/netbox-community/netbox/issues/4100) - Add device filter to component list views
-* [#4113](https://github.com/netbox-community/netbox/issues/4113) - Add bulk edit functionality for device type components
-* [#4116](https://github.com/netbox-community/netbox/issues/4116) - Enable bulk edit and delete functions for device component list views
-* [#4129](https://github.com/netbox-community/netbox/issues/4129) - Add buttons to delete individual device type components
-
-### Bug Fixes
-
-* [#3507](https://github.com/netbox-community/netbox/issues/3507) - Fix filtering IP addresses by multiple devices
-* [#3995](https://github.com/netbox-community/netbox/issues/3995) - Make dropdown menus in the navigation bar scrollable on small screens
-* [#4083](https://github.com/netbox-community/netbox/issues/4083) - Permit nullifying applicable choice fields via API requests
-* [#4089](https://github.com/netbox-community/netbox/issues/4089) - Selection of power outlet type during bulk update is optional
-* [#4090](https://github.com/netbox-community/netbox/issues/4090) - Render URL custom fields as links under object view
-* [#4091](https://github.com/netbox-community/netbox/issues/4091) - Fix filtering of objects by custom fields using UI search form
-* [#4099](https://github.com/netbox-community/netbox/issues/4099) - Linkify interfaces on global interfaces list
-* [#4108](https://github.com/netbox-community/netbox/issues/4108) - Avoid extraneous database queries when rendering search forms
-* [#4134](https://github.com/netbox-community/netbox/issues/4134) - Device power ports and outlets should inherit type from the parent device type
-* [#4137](https://github.com/netbox-community/netbox/issues/4137) - Disable occupied terminations when connecting a cable to a circuit
-* [#4138](https://github.com/netbox-community/netbox/issues/4138) - Restore device bay counts in rack elevation diagrams
-* [#4146](https://github.com/netbox-community/netbox/issues/4146) - Fix enforcement of secret role assignment for secret decryption
-* [#4150](https://github.com/netbox-community/netbox/issues/4150) - Correct YAML rendering of config contexts
-* [#4159](https://github.com/netbox-community/netbox/issues/4159) - Fix implementation of Redis caching configuration
-
----
-
-## v2.7.4 (2020-02-04)
-
-### Enhancements
-
-* [#568](https://github.com/netbox-community/netbox/issues/568) - Allow custom fields to be imported and exported using CSV
-* [#2921](https://github.com/netbox-community/netbox/issues/2921) - Replace tags filter with Select2 widget
-* [#3313](https://github.com/netbox-community/netbox/issues/3313) - Toggle config context display between JSON and YAML
-* [#3886](https://github.com/netbox-community/netbox/issues/3886) - Enable assigning config contexts by cluster and cluster group
-* [#4051](https://github.com/netbox-community/netbox/issues/4051) - Disable the `makemigrations` management command
-
-### Bug Fixes
-
-* [#4030](https://github.com/netbox-community/netbox/issues/4030) - Fix exception when bulk editing interfaces (revised)
-* [#4043](https://github.com/netbox-community/netbox/issues/4043) - Fix toggling of required fields in custom scripts
-* [#4049](https://github.com/netbox-community/netbox/issues/4049) - Restore missing `tags` field in IPAM service serializer
-* [#4052](https://github.com/netbox-community/netbox/issues/4052) - Fix error when bulk importing interfaces to virtual machines
-* [#4056](https://github.com/netbox-community/netbox/issues/4056) - Repair schema migration for Rack.outer_unit (from #3569)
-* [#4067](https://github.com/netbox-community/netbox/issues/4067) - Correct permission checked when creating a rack (vs. editing)
-* [#4071](https://github.com/netbox-community/netbox/issues/4071) - Enforce "view tag" permission on individual tag view
-* [#4079](https://github.com/netbox-community/netbox/issues/4079) - Fix assignment of power panel when bulk editing power feeds
-* [#4084](https://github.com/netbox-community/netbox/issues/4084) - Fix exception when creating an interface with tagged VLANs
-
----
-
-## v2.7.3 (2020-01-28)
-
-### Enhancements
-
-* [#3310](https://github.com/netbox-community/netbox/issues/3310) - Pre-select site/rack for B side when creating a new cable
-* [#3338](https://github.com/netbox-community/netbox/issues/3338) - Include circuit terminations in API representation of circuits
-* [#3509](https://github.com/netbox-community/netbox/issues/3509) - Add IP address variables for custom scripts
-* [#3978](https://github.com/netbox-community/netbox/issues/3978) - Add VRF filtering to search NAT IP
-* [#4005](https://github.com/netbox-community/netbox/issues/4005) - Include timezone context in webhook timestamps
-
-### Bug Fixes
-
-* [#3950](https://github.com/netbox-community/netbox/issues/3950) - Automatically select parent manufacturer when specifying initial device type during device creation
-* [#3982](https://github.com/netbox-community/netbox/issues/3982) - Restore tooltip for reservations on rack elevations
-* [#3983](https://github.com/netbox-community/netbox/issues/3983) - Permit the creation of multiple unnamed devices
-* [#3989](https://github.com/netbox-community/netbox/issues/3989) - Correct HTTP content type assignment for webhooks
-* [#3999](https://github.com/netbox-community/netbox/issues/3999) - Do not filter child results by null if non-required parent fields are blank
-* [#4008](https://github.com/netbox-community/netbox/issues/4008) - Toggle rack elevation face using front/rear strings
-* [#4017](https://github.com/netbox-community/netbox/issues/4017) - Remove redundant tenant field from cluster form
-* [#4019](https://github.com/netbox-community/netbox/issues/4019) - Restore border around background devices in rack elevations
-* [#4022](https://github.com/netbox-community/netbox/issues/4022) - Fix display of assigned IPs when filtering device interfaces
-* [#4025](https://github.com/netbox-community/netbox/issues/4025) - Correct display of cable status (various places)
-* [#4027](https://github.com/netbox-community/netbox/issues/4027) - Repair schema migration for #3569 to convert IP addresses with DHCP status
-* [#4028](https://github.com/netbox-community/netbox/issues/4028) - Correct URL patterns to match Unicode characters in tag slugs
-* [#4030](https://github.com/netbox-community/netbox/issues/4030) - Fix exception when setting interfaces to tagged mode in bulk
-* [#4033](https://github.com/netbox-community/netbox/issues/4033) - Restore missing comments field label of various bulk edit forms
-
----
-
-## v2.7.2 (2020-01-21)
-
-### Enhancements
-
-* [#3135](https://github.com/netbox-community/netbox/issues/3135) - Documented power modelling
-* [#3842](https://github.com/netbox-community/netbox/issues/3842) - Add 802.11ax interface type
-* [#3954](https://github.com/netbox-community/netbox/issues/3954) - Add `device_bays` filter for devices and device types
-
-### Bug Fixes
-
-* [#3721](https://github.com/netbox-community/netbox/issues/3721) - Allow Unicode characters in tag slugs
-* [#3923](https://github.com/netbox-community/netbox/issues/3923) - Indicate validation failure when using SSH-style RSA keys
-* [#3951](https://github.com/netbox-community/netbox/issues/3951) - Fix exception in webhook worker due to missing constant
-* [#3953](https://github.com/netbox-community/netbox/issues/3953) - Fix validation error when creating child devices
-* [#3960](https://github.com/netbox-community/netbox/issues/3960) - Fix legacy device status choice
-* [#3962](https://github.com/netbox-community/netbox/issues/3962) - Fix display of unnamed devices in rack elevations
-* [#3963](https://github.com/netbox-community/netbox/issues/3963) - Restore tooltip for devices in rack elevations
-* [#3964](https://github.com/netbox-community/netbox/issues/3964) - Show borders around devices in rack elevations
-* [#3965](https://github.com/netbox-community/netbox/issues/3965) - Indicate the presence of "background" devices in rack elevations
-* [#3966](https://github.com/netbox-community/netbox/issues/3966) - Fix filtering of device components by region/site
-* [#3967](https://github.com/netbox-community/netbox/issues/3967) - Resolve migration of "other" interface type
-
----
-
-## v2.7.1 (2020-01-16)
-
-### Bug Fixes
-
-* [#3941](https://github.com/netbox-community/netbox/issues/3941) - Fixed exception when attempting to assign IP to interface
-* [#3943](https://github.com/netbox-community/netbox/issues/3943) - Prevent rack elevation links from opening new tabs/windows
-* [#3944](https://github.com/netbox-community/netbox/issues/3944) - Fix AttributeError exception when viewing prefixes list
-
----
-
-## v2.7.0 (2020-01-16)
-
-**Note:** This release completely removes the topology map feature ([#2745](https://github.com/netbox-community/netbox/issues/2745)).
-
-**Note:** NetBox v2.7 is the last major release that will support Python 3.5. Beginning with NetBox v2.8, Python 3.6 or
-higher will be required.
-
-### New Features
-
-#### Enhanced Device Type Import ([#451](https://github.com/netbox-community/netbox/issues/451))
-
-NetBox now supports the import of device types and related component templates using definitions written in YAML or
-JSON. For example, the following will create a new device type with four network interfaces, two power ports, and a
-console port:
-
-```yaml
-manufacturer: Acme
-model: Packet Shooter 9000
-slug: packet-shooter-9000
-u_height: 1
-interfaces:
-  - name: ge-0/0/0
-    type: 1000base-t
-  - name: ge-0/0/1
-    type: 1000base-t
-  - name: ge-0/0/2
-    type: 1000base-t
-  - name: ge-0/0/3
-    type: 1000base-t
-power-ports:
-  - name: PSU0
-  - name: PSU1
-console-ports:
-  - name: Console
-```
-
-This new functionality replaces the old CSV-based import form, which did not allow for bulk import of component
-templates.
-
-#### Bulk Import of Device Components ([#822](https://github.com/netbox-community/netbox/issues/822))
-
-Device components such as console ports, power ports, and interfaces can now be imported in bulk to multiple devices in
-CSV format. Here's an example showing the bulk import of interfaces to several devices:
-
-```
-device,name,type
-Switch1,Vlan100,Virtual
-Switch1,Vlan200,Virtual
-Switch2,Vlan100,Virtual
-Switch2,Vlan200,Virtual
-```
-
-The import form for each type of device component is available under the "Devices" item in the navigation menu.
-
-#### External File Storage ([#1814](https://github.com/netbox-community/netbox/issues/1814))
-
-In prior releases, the only option for storing uploaded files (e.g. image attachments) was to save them to the local
-filesystem on the NetBox server. This release introduces support for several remote storage backends provided by the
-[`django-storages`](https://django-storages.readthedocs.io/en/stable/) library. These include:
-
-* Amazon S3
-* ApacheLibcloud
-* Azure Storage
-* netbox-community Spaces
-* Dropbox
-* FTP
-* Google Cloud Storage
-* SFTP
-
-To enable remote file storage, first install the `django-storages` package:
-
-```
-pip install django-storages
-```
-
-Then, set the appropriate storage backend and its configuration in `configuration.py`. Here's an example using Amazon
-S3:
-
-```python
-STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage'
-STORAGE_CONFIG = {
-    'AWS_ACCESS_KEY_ID': '<Key>',
-    'AWS_SECRET_ACCESS_KEY': '<Secret>',
-    'AWS_STORAGE_BUCKET_NAME': 'netbox',
-    'AWS_S3_REGION_NAME': 'eu-west-1',
-}
-```
-
-Thanks to [@steffann](https://github.com/steffann) for contributing this work!
-
-#### Rack Elevations Rendered via SVG ([#2248](https://github.com/netbox-community/netbox/issues/2248))
-
-NetBox v2.7 introduces a new method of rendering rack elevations as an
-[SVG image](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics) via a REST API endpoint. This replaces the prior
-method of rendering elevations using pure HTML and CSS, which was cumbersome and had several shortcomings. Rendering
-rack elevations as SVG images via the REST API allows users to retrieve and make use of the drawings in their own
-tooling. This also opens the door to other feature requests related to rack elevations in the NetBox backlog.
-
-This feature implements a new REST API endpoint:
-
-```
-/api/dcim/racks/<id>/elevation/
-```
-
-By default, this endpoint returns a paginated JSON response representing each rack unit in the given elevation. This is
-the same response returned by the existing rack units detail endpoint at `/api/dcim/racks/<id>/units/`, which will be
-removed in v2.8 (see [#3753](https://github.com/netbox-community/netbox/issues/3753)).
-
-To render the elevation as an SVG image, include the `render=svg` query parameter in the request. You may also control
-the width and height of the elevation drawing (in pixels) by passing the `unit_width` and `unit_height` parameters. (The
-default values for these parameters are 230 and 20, respectively.) Additionally, the `face` parameter may be used to
-request either the `front` or `rear` of the elevation. Below is in example request:
-
-```
-/api/dcim/racks/<id>/elevation/?render=svg&face=rear&unit_width=300&unit_height=35
-```
-
-Thanks to [@hellerve](https://github.com/hellerve) for doing the heavy lifting on this!
-
-### Changes
-
-#### Topology Maps Removed ([#2745](https://github.com/netbox-community/netbox/issues/2745))
-
-The topology maps feature has been removed to help focus NetBox development efforts. Please replicate any required data
-to another source before upgrading NetBox to v2.7, as any existing topology maps will be deleted.
-
-#### Supervisor Replaced with systemd ([#2902](https://github.com/netbox-community/netbox/issues/2902))
-
-The NetBox [installation documentation](https://docs.netbox.dev/en/stable/installation/) has been updated to
-provide instructions for managing the WSGI and RQ services using systemd instead of supervisor. This removes the need to
-install supervisor and simplifies administration of the processes.
-
-#### Redis Configuration ([#3282](https://github.com/netbox-community/netbox/issues/3282))
-
-NetBox v2.6 introduced request caching and added the `CACHE_DATABASE` option to the existing `REDIS` database
-configuration parameter. This did not, however, allow for using two different Redis connections for the separate caching
-and webhook queuing functions. This release modifies the `REDIS` parameter to accept two discrete subsections named
-`webhooks` and `caching`. This requires modification of the `REDIS` parameter in `configuration.py` as follows:
-
-Old Redis configuration:
-
-```python
-REDIS = {
-    'HOST': 'localhost',
-    'PORT': 6379,
-    'PASSWORD': '',
-    'DATABASE': 0,
-    'CACHE_DATABASE': 1,
-    'DEFAULT_TIMEOUT': 300,
-    'SSL': False,
-}
-```
-
-New Redis configuration:
-
-```python
-REDIS = {
-    'webhooks': {
-        'HOST': 'redis.example.com',
-        'PORT': 1234,
-        'PASSWORD': 'foobar',
-        'DATABASE': 0,
-        'DEFAULT_TIMEOUT': 300,
-        'SSL': False,
-    },
-    'caching': {
-        'HOST': 'localhost',
-        'PORT': 6379,
-        'PASSWORD': '',
-        'DATABASE': 1,
-        'DEFAULT_TIMEOUT': 300,
-        'SSL': False,
-    }
-}
-```
-
-Note that the `CACHE_DATABASE` parameter has been removed and the connection settings have been duplicated for both
-`webhooks` and `caching`. This allows the user to make use of separate Redis instances if desired. It is fine to use the
-same Redis service for both functions, although the database identifiers should be different.
-
-#### WEBHOOKS_ENABLED Configuration Setting Removed ([#3408](https://github.com/netbox-community/netbox/issues/3408))
-
-As `django-rq` is now a required library, NetBox assumes that the RQ worker process is running. The installation and
-upgrade documentation has been updated to reflect this, and the `WEBHOOKS_ENABLED` configuration parameter is no longer
-used. Please ensure that both the NetBox WSGI service and the RQ worker process are running on all production
-installations.
-
-#### API Choice Fields Now Use String Values ([#3569](https://github.com/netbox-community/netbox/issues/3569))
-
-NetBox's REST API presents fields which reference a particular choice as a dictionary with two keys: `value` and
-`label`. In previous versions, `value` was an integer which represented a particular choice in the database. This has
-been changed to a more human-friendly "slug" string, which is essentially a simplified version of the choice's `label`.
-
-For example, The site model's `status` field was previously represented as:
-
-```json
-"status": {
-    "value": 1,
-    "label": "Active"
-},
-```
-
-In NetBox v2.7, it now looks like this:
-
-```json
-"status": {
-    "value": "active",
-    "label": "Active",
-    "id": 1
-},
-```
-
-This change allows for much more intuitive representation and manipulation of values, and removes the need for API
-consumers to maintain local mappings of static integer values.
-
-Note that that all v2.7 releases will continue to accept the legacy integer values in write requests (`POST`, `PUT`, and
-`PATCH`) to maintain backward compatibility. Additionally, the legacy numeric identifier is conveyed in the `id` field
-for convenient reference as consumers adopt to the new string values. This behavior will be discontinued in NetBox v2.8.
-
-### Enhancements
-
-* [#33](https://github.com/netbox-community/netbox/issues/33) - Add ability to clone objects (pre-populate form fields)
-* [#648](https://github.com/netbox-community/netbox/issues/648) - Pre-populate form fields when selecting "create and
-  add another"
-* [#792](https://github.com/netbox-community/netbox/issues/792) - Add power port and power outlet types
-* [#1865](https://github.com/netbox-community/netbox/issues/1865) - Add console port and console server port types
-* [#2669](https://github.com/netbox-community/netbox/issues/2669) - Relax uniqueness constraint on device and VM names
-* [#2902](https://github.com/netbox-community/netbox/issues/2902) - Replace `supervisord` with `systemd`
-* [#3455](https://github.com/netbox-community/netbox/issues/3455) - Add tenant assignment to virtual machine clusters
-* [#3520](https://github.com/netbox-community/netbox/issues/3520) - Add Jinja2 template support for graphs
-* [#3525](https://github.com/netbox-community/netbox/issues/3525) - Enable IP address filtering using multiple address
-  parameters
-* [#3564](https://github.com/netbox-community/netbox/issues/3564) - Add list views for all device components
-* [#3538](https://github.com/netbox-community/netbox/issues/3538) - Introduce a REST API endpoint for executing custom
-  scripts
-* [#3655](https://github.com/netbox-community/netbox/issues/3655) - Add `description` field to organizational models
-* [#3664](https://github.com/netbox-community/netbox/issues/3664) - Enable applying configuration contexts by tags
-* [#3706](https://github.com/netbox-community/netbox/issues/3706) - Increase `available_power` maximum value on
-  PowerFeed
-* [#3731](https://github.com/netbox-community/netbox/issues/3731) - Change Graph.type to a ContentType foreign key field
-* [#3801](https://github.com/netbox-community/netbox/issues/3801) - Use YAML for export of device types
-
-### Bug Fixes
-
-* [#3830](https://github.com/netbox-community/netbox/issues/3830) - Ensure deterministic ordering for all models
-* [#3900](https://github.com/netbox-community/netbox/issues/3900) - Fix exception when deleting device types
-* [#3914](https://github.com/netbox-community/netbox/issues/3914) - Fix interface filter field when unauthenticated
-* [#3919](https://github.com/netbox-community/netbox/issues/3919) - Fix utilization graph extending out of bounds when
-  utilization > 100%
-* [#3927](https://github.com/netbox-community/netbox/issues/3927) - Fix exception when deleting devices with secrets
-  assigned
-* [#3930](https://github.com/netbox-community/netbox/issues/3930) - Fix API rendering of the `family` field for
-  aggregates
-
-### Bug Fixes (From Beta)
-
-* [#3868](https://github.com/netbox-community/netbox/issues/3868) - Fix creation of interfaces for virtual machines
-* [#3878](https://github.com/netbox-community/netbox/issues/3878) - Fix database migration for cable status field
-
-### API Changes
-
-* Choice fields now use human-friendly strings for their values instead of integers (see
-  [#3569](https://github.com/netbox-community/netbox/issues/3569)).
-* Introduced the `/api/extras/scripts/` endpoint for retrieving and executing custom scripts
-* circuits.CircuitType: Added field `description`
-* dcim.ConsolePort: Added field `type`
-* dcim.ConsolePortTemplate: Added field `type`
-* dcim.ConsoleServerPort: Added field `type`
-* dcim.ConsoleServerPortTemplate: Added field `type`
-* dcim.DeviceRole: Added field `description`
-* dcim.PowerPort: Added field `type`
-* dcim.PowerPortTemplate: Added field `type`
-* dcim.PowerOutlet: Added field `type`
-* dcim.PowerOutletTemplate: Added field `type`
-* dcim.RackRole: Added field `description`
-* extras.Graph: Added field `template_language` (to indicate `django` or `jinja2`)
-* extras.Graph: The `type` field has been changed to a content type foreign key. Models are specified as
-  `<app>.<model>`; e.g. `dcim.site`.
-* ipam.Role: Added field `description`
-* secrets.SecretRole: Added field `description`
-* virtualization.Cluster: Added field `tenant`

+ 0 - 270
docs/release-notes/version-2.8.md

@@ -1,270 +0,0 @@
-# NetBox v2.8
-
-## v2.8.9 (2020-08-04)
-
-### Enhancements
-
-* [#4898](https://github.com/netbox-community/netbox/issues/4898) - Add MAC address search field to interfaces list
-* [#4899](https://github.com/netbox-community/netbox/issues/4899) - Add MAC address column to interfaces table
-
-### Bug Fixes
-
-* [#4455](https://github.com/netbox-community/netbox/issues/4455) - Fix ordering of prefixes beneath aggregate when available space is hidden
-* [#4875](https://github.com/netbox-community/netbox/issues/4875) - Fix documentation for image attachments
-* [#4876](https://github.com/netbox-community/netbox/issues/4876) - Fix labels for sites in staging or decommissioning status
-* [#4880](https://github.com/netbox-community/netbox/issues/4880) - Fix removal of tagged VLANs if not assigned in bulk interface editing
-* [#4887](https://github.com/netbox-community/netbox/issues/4887) - Don't disable NAPALM tabs when device has no primary IP
-* [#4894](https://github.com/netbox-community/netbox/issues/4894) - Fix display of device/VM counts on platforms list
-* [#4895](https://github.com/netbox-community/netbox/issues/4895) - Force UTF-8 encoding when embedding model documentation
-* [#4910](https://github.com/netbox-community/netbox/issues/4910) - Unpin redis dependency to fix exception in RQ worker
-* [#4926](https://github.com/netbox-community/netbox/issues/4926) - Fix ordering of VM interfaces in REST API endpoint
-* [#4927](https://github.com/netbox-community/netbox/issues/4927) - Fix validation error when updating an existing secret
-* [#4929](https://github.com/netbox-community/netbox/issues/4929) - Correct log message when creating a new object
-
----
-
-## v2.8.8 (2020-07-21)
-
-### Enhancements
-
-* [#4805](https://github.com/netbox-community/netbox/issues/4805) - Improve handling of plugin loading errors
-* [#4829](https://github.com/netbox-community/netbox/issues/4829) - Add NEMA 15 power port and outlet types
-* [#4831](https://github.com/netbox-community/netbox/issues/4831) - Allow NAPALM to resolve device name when primary IP is not set
-* [#4854](https://github.com/netbox-community/netbox/issues/4854) - Add staging and decommissioning statuses for sites
-
-### Bug Fixes
-
-* [#3240](https://github.com/netbox-community/netbox/issues/3240) - Correct OpenAPI definition for available-prefixes endpoint
-* [#4595](https://github.com/netbox-community/netbox/issues/4595) - Ensure consistent display of non-racked and child devices on rack view
-* [#4803](https://github.com/netbox-community/netbox/issues/4803) - Return IP family (4 or 6) as integer rather than string
-* [#4821](https://github.com/netbox-community/netbox/issues/4821) - Restrict group options by selected site when bulk editing VLANs
-* [#4835](https://github.com/netbox-community/netbox/issues/4835) - Support passing multiple initial values for multiple choice fields
-* [#4838](https://github.com/netbox-community/netbox/issues/4838) - Fix rack power utilization display for racks without devices
-* [#4851](https://github.com/netbox-community/netbox/issues/4851) - Show locally connected peer on circuit terminations
-* [#4856](https://github.com/netbox-community/netbox/issues/4856) - Redirect user back to circuit after connecting a termination
-* [#4872](https://github.com/netbox-community/netbox/issues/4872) - Enable filtering virtual machine interfaces by tag
-
----
-
-## v2.8.7 (2020-07-02)
-
-### Enhancements
-
-* [#4796](https://github.com/netbox-community/netbox/issues/4796) - Introduce configuration parameters for default rack elevation size
-* [#4802](https://github.com/netbox-community/netbox/issues/4802) - Allow changing page size when displaying only a single page of results
-
-### Bug Fixes
-
-* [#4695](https://github.com/netbox-community/netbox/issues/4695) - Expose cable termination type choices in OpenAPI spec
-* [#4708](https://github.com/netbox-community/netbox/issues/4708) - Relax connection constraints for multi-position rear ports
-* [#4766](https://github.com/netbox-community/netbox/issues/4766) - Fix redirect after login when `next` is not specified
-* [#4771](https://github.com/netbox-community/netbox/issues/4771) - Fix add/remove tag population when bulk editing objects
-* [#4772](https://github.com/netbox-community/netbox/issues/4772) - Fix "brief" format for the secrets REST API endpoint
-* [#4774](https://github.com/netbox-community/netbox/issues/4774) - Fix exception when deleting a device with device bays
-* [#4775](https://github.com/netbox-community/netbox/issues/4775) - Allow selecting an alternate device type when creating component templates
-
----
-
-## v2.8.6 (2020-06-15)
-
-### Enhancements
-
-* [#4698](https://github.com/netbox-community/netbox/issues/4698) - Improve display of template code for object in admin UI
-* [#4717](https://github.com/netbox-community/netbox/issues/4717) - Introduce `ALLOWED_URL_SCHEMES` configuration parameter to mitigate dangerous hyperlinks
-* [#4744](https://github.com/netbox-community/netbox/issues/4744) - Hide "IP addresses" tab when viewing a container prefix
-* [#4755](https://github.com/netbox-community/netbox/issues/4755) - Enable creation of rack reservations directly from navigation menu
-* [#4761](https://github.com/netbox-community/netbox/issues/4761) - Enable tag assignment during bulk creation of IP addresses
-
-### Bug Fixes
-
-* [#4674](https://github.com/netbox-community/netbox/issues/4674) - Fix API definition for available prefix and IP address endpoints
-* [#4702](https://github.com/netbox-community/netbox/issues/4702) - Catch IntegrityError exception when adding a non-unique secret
-* [#4707](https://github.com/netbox-community/netbox/issues/4707) - Fix `prefix_count` population on VLAN API serializer
-* [#4710](https://github.com/netbox-community/netbox/issues/4710) - Fix merging of form fields among custom scripts
-* [#4725](https://github.com/netbox-community/netbox/issues/4725) - Fix "brief" rendering of various REST API endpoints
-* [#4736](https://github.com/netbox-community/netbox/issues/4736) - Add cable trace endpoints for pass-through ports
-* [#4737](https://github.com/netbox-community/netbox/issues/4737) - Fix display of role labels in virtual machines table
-* [#4743](https://github.com/netbox-community/netbox/issues/4743) - Allow users to create "next available" IPs without needing permission to create prefixes
-* [#4756](https://github.com/netbox-community/netbox/issues/4756) - Filter parent group by site when creating rack groups
-* [#4760](https://github.com/netbox-community/netbox/issues/4760) - Enable power port template assignment when bulk editing power outlet templates
-
----
-
-## v2.8.5 (2020-05-26)
-
-**Note:** The minimum required version of PostgreSQL is now 9.6.
-
-### Enhancements
-
-* [#4650](https://github.com/netbox-community/netbox/issues/4650) - Expose `INTERNAL_IPS` configuration parameter
-* [#4651](https://github.com/netbox-community/netbox/issues/4651) - Add `csrf_token` context for plugin templates
-* [#4652](https://github.com/netbox-community/netbox/issues/4652) - Add permissions context for plugin templates
-* [#4665](https://github.com/netbox-community/netbox/issues/4665) - Add NEMA L14 and L21 power port/outlet types
-* [#4672](https://github.com/netbox-community/netbox/issues/4672) - Set default color for rack and devices roles
-
-### Bug Fixes
-
-* [#3304](https://github.com/netbox-community/netbox/issues/3304) - Fix caching invalidation issue related to device/virtual machine primary IP addresses
-* [#4525](https://github.com/netbox-community/netbox/issues/4525) - Allow passing initial data to custom script MultiObjectVar
-* [#4644](https://github.com/netbox-community/netbox/issues/4644) - Fix ordering of services table by parent
-* [#4646](https://github.com/netbox-community/netbox/issues/4646) - Correct UI link for reports with custom name
-* [#4647](https://github.com/netbox-community/netbox/issues/4647) - Fix caching invalidation issue related to assigning new IP addresses to interfaces
-* [#4648](https://github.com/netbox-community/netbox/issues/4648) - Fix bulk CSV import of child devices
-* [#4649](https://github.com/netbox-community/netbox/issues/4649) - Fix interface assignment for bulk-imported IP addresses
-* [#4676](https://github.com/netbox-community/netbox/issues/4676) - Set default value of `REMOTE_AUTH_AUTO_CREATE_USER` as `False` in docs
-* [#4684](https://github.com/netbox-community/netbox/issues/4684) - Respect `comments` field when importing device type in YAML/JSON format
-
----
-
-## v2.8.4 (2020-05-13)
-
-### Enhancements
-
-* [#4632](https://github.com/netbox-community/netbox/issues/4632) - Extend email configuration parameters to support SSL/TLS
-
-### Bug Fixes
-
-* [#4598](https://github.com/netbox-community/netbox/issues/4598) - Display error message when invalid cable length is specified
-* [#4604](https://github.com/netbox-community/netbox/issues/4604) - Multi-position rear ports may only be connected to other rear ports
-* [#4607](https://github.com/netbox-community/netbox/issues/4607) - Missing Contextual help for API Tokens
-* [#4613](https://github.com/netbox-community/netbox/issues/4613) - Fix tag assignment on config contexts (regression from #4527)
-* [#4617](https://github.com/netbox-community/netbox/issues/4617) - Restore IP prefix depth notation in list view
-* [#4629](https://github.com/netbox-community/netbox/issues/4629) - Replicate assigned interface when cloning IP addresses
-* [#4633](https://github.com/netbox-community/netbox/issues/4633) - Bump django-rq to v2.3.2 to fix ImportError with rq 1.4.0
-* [#4634](https://github.com/netbox-community/netbox/issues/4634) - Inventory Item List view exception caused by incorrect accessor definition 
-
----
-
-## v2.8.3 (2020-05-06)
-
-### Bug Fixes
-
-* [#4593](https://github.com/netbox-community/netbox/issues/4593) - Fix AttributeError exception when viewing object lists as a non-authenticated user
-
----
-
-## v2.8.2 (2020-05-06)
-
-### Enhancements
-
-* [#492](https://github.com/netbox-community/netbox/issues/492) - Enable toggling and rearranging table columns
-* [#3147](https://github.com/netbox-community/netbox/issues/3147) - Allow specifying related objects by arbitrary attribute during CSV import
-* [#3064](https://github.com/netbox-community/netbox/issues/3064) - Include tags in object lists as a toggleable table column
-* [#3294](https://github.com/netbox-community/netbox/issues/3294) - Implement mechanism for storing user preferences
-* [#4421](https://github.com/netbox-community/netbox/issues/4421) - Retain user's preference for config context format
-* [#4502](https://github.com/netbox-community/netbox/issues/4502) - Enable configuration of proxies for outbound HTTP requests
-* [#4531](https://github.com/netbox-community/netbox/issues/4531) - Retain user's preference for page length
-* [#4554](https://github.com/netbox-community/netbox/issues/4554) - Add ServerTech's HDOT Cx power outlet type
-
-### Bug Fixes
-
-* [#4527](https://github.com/netbox-community/netbox/issues/4527) - Fix assignment of certain tags to config contexts
-* [#4545](https://github.com/netbox-community/netbox/issues/4545) - Removed all squashed schema migrations to allow direct upgrades from very old releases
-* [#4548](https://github.com/netbox-community/netbox/issues/4548) - Fix tracing cables through a single RearPort
-* [#4549](https://github.com/netbox-community/netbox/issues/4549) - Fix encoding unicode webhook body data
-* [#4556](https://github.com/netbox-community/netbox/issues/4556) - Update form for adding devices to clusters
-* [#4578](https://github.com/netbox-community/netbox/issues/4578) - Prevent setting 0U height on device type with racked instances
-* [#4584](https://github.com/netbox-community/netbox/issues/4584) - Ensure consistent support for filtering objects by `id` across all REST API endpoints
-* [#4588](https://github.com/netbox-community/netbox/issues/4588) - Restore ability to add/remove tags on services, virtual chassis in bulk
-
----
-
-## v2.8.1 (2020-04-23)
-
-### Notes
-
-In accordance with the fix in [#4459](https://github.com/netbox-community/netbox/issues/4459), users that are experiencing invalid nested data with
-regions, rack groups, or tenant groups can perform a one-time operation using the NetBox shell to rebuild the correct nested relationships after upgrading:
-
-```text
-$ python netbox/manage.py nbshell
-### NetBox interactive shell (localhost)
-### Python 3.6.4 | Django 3.0.5 | NetBox 2.8.1
-### lsmodels() will show available models. Use help(<model>) for more info.
->>> Region.objects.rebuild()
->>> RackGroup.objects.rebuild()
->>> TenantGroup.objects.rebuild()
-```
-
-### Enhancements
-
-* [#4464](https://github.com/netbox-community/netbox/issues/4464) - Add 21-inch rack width (ETSI)
-
-### Bug Fixes
-
-* [#2994](https://github.com/netbox-community/netbox/issues/2994) - Prevent modifying termination points of existing cable to ensure end-to-end path integrity
-* [#3356](https://github.com/netbox-community/netbox/issues/3356) - Correct Swagger schema specification for the available prefixes/IPs API endpoints
-* [#4139](https://github.com/netbox-community/netbox/issues/4139) - Enable assigning all relevant attributes during bulk device/VM component creation
-* [#4336](https://github.com/netbox-community/netbox/issues/4336) - Ensure interfaces without a subinterface ID are ordered before subinterface zero
-* [#4361](https://github.com/netbox-community/netbox/issues/4361) - Fix Type of `connection_state` in Swagger schema
-* [#4388](https://github.com/netbox-community/netbox/issues/4388) - Fix detection of connected endpoints when connecting rear ports
-* [#4459](https://github.com/netbox-community/netbox/issues/4459) - Fix caching issue resulting in erroneous nested data for regions, rack groups, and tenant groups
-* [#4489](https://github.com/netbox-community/netbox/issues/4489) - Fix display of parent/child role on device type view
-* [#4496](https://github.com/netbox-community/netbox/issues/4496) - Fix exception when validating certain models via REST API
-* [#4510](https://github.com/netbox-community/netbox/issues/4510) - Enforce address family for device primary IPv4/v6 addresses
-
----
-
-## v2.8.0 (2020-04-13)
-
-**NOTE:** Beginning with release 2.8.0, NetBox requires Python 3.6 or later.
-
-### New Features (Beta)
-
-This releases introduces two new features in beta status. While they are expected to be functional, their precise implementation is subject to change during the v2.8 release cycle. It is recommended to wait until NetBox v2.9 to deploy them in production.
-
-#### Remote Authentication Support ([#2328](https://github.com/netbox-community/netbox/issues/2328))
-
-Several new configuration parameters provide support for authenticating an incoming request based on the value of a specific HTTP header. This can be leveraged to employ remote authentication via an nginx or Apache plugin, directing NetBox to create and configure a local user account as needed. The configuration parameters are:
-
-* `REMOTE_AUTH_ENABLED` - Enables remote authentication (disabled by default)
-* `REMOTE_AUTH_HEADER` - The name of the HTTP header which conveys the username
-* `REMOTE_AUTH_AUTO_CREATE_USER` - Enables the automatic creation of new users (disabled by default)
-* `REMOTE_AUTH_DEFAULT_GROUPS` - A list of groups to assign newly created users
-* `REMOTE_AUTH_DEFAULT_PERMISSIONS` - A list of permissions to assign newly created users
-
-If further customization of remote authentication is desired (for instance, if you want to pass group/permission information via HTTP headers as well), NetBox allows you to inject a custom [Django authentication backend](https://docs.djangoproject.com/en/stable/topics/auth/customizing/) to retain full control over the authentication and configuration of remote users.
-
-#### Plugins ([#3351](https://github.com/netbox-community/netbox/issues/3351))
-
-This release introduces support for custom plugins, which can be used to extend NetBox's functionality beyond what the core product provides. For example, plugins can be used to:
-
-* Add new Django models
-* Provide new views with custom templates
-* Inject custom template into object views
-* Introduce new API endpoints
-* Add custom request/response middleware
-
-For NetBox plugins to be recognized, they must be installed and added by name to the `PLUGINS` configuration parameter. (Plugin support is disabled by default.) Plugins can be configured under the `PLUGINS_CONFIG` parameter. More information can be found the in the [plugins documentation](https://docs.netbox.dev/en/stable/plugins/).
-
-### Enhancements
-
-* [#1754](https://github.com/netbox-community/netbox/issues/1754) - Added support for nested rack groups
-* [#3939](https://github.com/netbox-community/netbox/issues/3939) - Added support for nested tenant groups
-* [#4078](https://github.com/netbox-community/netbox/issues/4078) - Standardized description fields across all models
-* [#4195](https://github.com/netbox-community/netbox/issues/4195) - Enabled application logging (see [logging configuration](https://docs.netbox.dev/en/stable/configuration/optional-settings/#logging))
-
-### Bug Fixes
-
-* [#4474](https://github.com/netbox-community/netbox/issues/4474) - Fix population of device types when bulk editing devices
-* [#4476](https://github.com/netbox-community/netbox/issues/4476) - Correct typo in slugs for Infiniband interface types
-
-### API Changes
-
-* The `_choices` API endpoints have been removed. Instead, use an `OPTIONS` request to a model's endpoint to view the available values for all fields. ([#3416](https://github.com/netbox-community/netbox/issues/3416))
-* The `id__in` filter has been removed from all models ([#4313](https://github.com/netbox-community/netbox/issues/4313)). Use the format `?id=1&id=2` instead.
-* dcim.Manufacturer: Added a `description` field
-* dcim.Platform: Added a `description` field
-* dcim.Rack: The `/api/dcim/racks/<pk>/units/` endpoint has been replaced with `/api/dcim/racks/<pk>/elevation/`.
-* dcim.RackGroup: Added a `description` field
-* dcim.Region: Added a `description` field
-* extras.Tag: Renamed `comments` to `description`; truncated length to 200 characters; removed Markdown rendering
-* ipam.RIR: Added a `description` field
-* ipam.VLANGroup: Added a `description` field
-* tenancy.TenantGroup: Added a `description` field
-* virtualization.ClusterGroup: Added a `description` field
-* virtualization.ClusterType: Added a `description` field
-
-### Other Changes
-
-* [#4081](https://github.com/netbox-community/netbox/issues/4081) - The `family` field has been removed from the Aggregate, Prefix, and IPAddress models. The field remains available in the API representations of these models, however the column has been removed from the database table.

+ 0 - 335
docs/release-notes/version-2.9.md

@@ -1,335 +0,0 @@
-# NetBox v2.9
-
-## v2.9.11 (2020-12-11)
-
-### Enhancements
-
-* [#5424](https://github.com/netbox-community/netbox/issues/5424) - Allow passing Python code to `nbshell` using `--command`
-* [#5439](https://github.com/netbox-community/netbox/issues/5439) - Add CS and SN fiber port types
-
-### Bug Fixes
-
-* [#5383](https://github.com/netbox-community/netbox/issues/5383) - Fix setting user password via REST API
-* [#5396](https://github.com/netbox-community/netbox/issues/5396) - Fix uniqueness constraint for virtual machine names
-* [#5387](https://github.com/netbox-community/netbox/issues/5387) - Fix error when rendering config contexts when objects have multiple tags assigned
-* [#5407](https://github.com/netbox-community/netbox/issues/5407) - Add direct link to secret on secrets list
-* [#5408](https://github.com/netbox-community/netbox/issues/5408) - Fix updating secrets without setting new plaintext
-* [#5410](https://github.com/netbox-community/netbox/issues/5410) - Restore tags field on cable connection forms
-* [#5433](https://github.com/netbox-community/netbox/issues/5433) - Exclude SVG files from front/rear image upload for device types (currently unsupported)
-* [#5436](https://github.com/netbox-community/netbox/issues/5436) - Show assigned IP addresses in interfaces list
-* [#5446](https://github.com/netbox-community/netbox/issues/5446) - Fix validation for plugin version and required settings
-
----
-
-## v2.9.10 (2020-11-24)
-
-### Enhancements
-
-* [#5319](https://github.com/netbox-community/netbox/issues/5319) - Add USB types for power ports and outlets
-* [#5337](https://github.com/netbox-community/netbox/issues/5337) - Add "splice" type for pass-through ports
-
-### Bug Fixes
-
-* [#5235](https://github.com/netbox-community/netbox/issues/5235) - Fix exception when editing IP address with a NAT IP assigned to a non-racked device
-* [#5309](https://github.com/netbox-community/netbox/issues/5309) - Avoid extraneous database queries when manipulating objects
-* [#5345](https://github.com/netbox-community/netbox/issues/5345) - Fix non-deterministic ordering of prefixes and IP addresses
-* [#5350](https://github.com/netbox-community/netbox/issues/5350) - Filter available racks by selected group when creating a rack reservation
-* [#5355](https://github.com/netbox-community/netbox/issues/5355) - Limit rack groups by selected site when editing a rack
-* [#5356](https://github.com/netbox-community/netbox/issues/5356) - Populate manufacturer field when adding a device component template
-* [#5360](https://github.com/netbox-community/netbox/issues/5360) - Clear VLAN assignments when setting interface mode to none
-
----
-
-## v2.9.9 (2020-11-09)
-
-### Enhancements
-
-* [#5304](https://github.com/netbox-community/netbox/issues/5304) - Return server error messages as JSON when handling REST API requests
-* [#5310](https://github.com/netbox-community/netbox/issues/5310) - Link to rack groups within rack list table
-* [#5327](https://github.com/netbox-community/netbox/issues/5327) - Be more strict when capturing anticipated ImportError exceptions
-
-### Bug Fixes
-
-* [#5271](https://github.com/netbox-community/netbox/issues/5271) - Fix auto-population of region field when editing a device
-* [#5314](https://github.com/netbox-community/netbox/issues/5314) - Fix config context rendering when multiple tags are assigned to an object
-* [#5316](https://github.com/netbox-community/netbox/issues/5316) - Dry running scripts should not trigger webhooks
-* [#5324](https://github.com/netbox-community/netbox/issues/5324) - Add missing template extension tags for plugins for VM interface view
-* [#5328](https://github.com/netbox-community/netbox/issues/5328) - Fix CreatedUpdatedFilterTest when running in non-UTC timezone
-* [#5331](https://github.com/netbox-community/netbox/issues/5331) - Fix filtering of sites by null region
-
----
-
-## v2.9.8 (2020-10-30)
-
-### Enhancements
-
-* [#4559](https://github.com/netbox-community/netbox/issues/4559) - Improve device/VM context data rendering performance
-
-### Bug Fixes
-
-* [#3672](https://github.com/netbox-community/netbox/issues/3672) - Fix a caching issue causing incorrect related object counts in API responses
-* [#5113](https://github.com/netbox-community/netbox/issues/5113) - Fix incorrect caching of permission object assignments to user groups in the admin panel
-* [#5243](https://github.com/netbox-community/netbox/issues/5243) - Redirect user to appropriate tab after modifying device components
-* [#5273](https://github.com/netbox-community/netbox/issues/5273) - Fix exception when validating a new permission with no models selected
-* [#5282](https://github.com/netbox-community/netbox/issues/5282) - Fix high CPU load when LDAP authentication is enabled
-* [#5285](https://github.com/netbox-community/netbox/issues/5285) - Plugins no longer need to define `app_name` for API URLs to be included in the root view
-
----
-
-## v2.9.7 (2020-10-12)
-
-### Bug Fixes
-
-* [#5231](https://github.com/netbox-community/netbox/issues/5231) - Fix KeyError exception when viewing object with custom link and debugging is disabled
-
----
-
-## v2.9.6 (2020-10-09)
-
-### Bug Fixes
-
-* [#5229](https://github.com/netbox-community/netbox/issues/5229) - Fix AttributeError exception when LDAP authentication is enabled
-
----
-
-## v2.9.5 (2020-10-09)
-
-### Enhancements
-
-* [#5202](https://github.com/netbox-community/netbox/issues/5202) - Extend the available context data when rendering custom links
-
-### Bug Fixes
-
-* [#4523](https://github.com/netbox-community/netbox/issues/4523) - Populate site vlan list when bulk editing interfaces under certain circumstances
-* [#5174](https://github.com/netbox-community/netbox/issues/5174) - Ensure consistent alignment of rack elevations
-* [#5175](https://github.com/netbox-community/netbox/issues/5175) - Fix toggling of rack elevation order
-* [#5184](https://github.com/netbox-community/netbox/issues/5184) - Fix missing Power Utilization
-* [#5197](https://github.com/netbox-community/netbox/issues/5197) - Limit duplicate IPs shown on IP address view
-* [#5199](https://github.com/netbox-community/netbox/issues/5199) - Change default LDAP logging to INFO
-* [#5201](https://github.com/netbox-community/netbox/issues/5201) - Fix missing querystring when bulk editing/deleting VLAN Group VLANs when selecting "select all x items matching query"
-* [#5206](https://github.com/netbox-community/netbox/issues/5206) - Apply user pagination preferences to all paginated object lists
-* [#5211](https://github.com/netbox-community/netbox/issues/5211) - Add missing `has_primary_ip` filter for virtual machines
-* [#5217](https://github.com/netbox-community/netbox/issues/5217) - Prevent erroneous removal of prefetched GenericForeignKey data from tables
-* [#5218](https://github.com/netbox-community/netbox/issues/5218) - Raise validation error if a power port's `allocated_draw` exceeds its `maximum_draw`
-* [#5220](https://github.com/netbox-community/netbox/issues/5220) - Fix API patch request against IP Address endpoint with null assigned_object_type 
-* [#5221](https://github.com/netbox-community/netbox/issues/5221) - Fix bulk component creation for virtual machines
-* [#5224](https://github.com/netbox-community/netbox/issues/5224) - Don't allow a rear port to have fewer positions than the number of mapped front ports
-* [#5226](https://github.com/netbox-community/netbox/issues/5226) - Custom choice fields should be blank initially if no default choice has been designated
-
----
-
-## v2.9.4 (2020-09-23)
-
-**NOTE:** This release removes support for the `DEFAULT_TIMEOUT` parameter under `REDIS` database configuration. Set `RQ_DEFAULT_TIMEOUT` as a global configuration parameter instead.
-
-**NOTE:** Any permissions referencing the legacy ReportResult model (e.g. `extras.view_reportresult`) should be updated to reference the Report model.
-
-### Enhancements
-
-* [#1755](https://github.com/netbox-community/netbox/issues/1755) - Toggle order in which rack elevations are displayed
-* [#5128](https://github.com/netbox-community/netbox/issues/5128) - Increase maximum rear port positions from 64 to 1024
-* [#5134](https://github.com/netbox-community/netbox/issues/5134) - Display full hierarchy in breadcrumbs for sites/racks
-* [#5149](https://github.com/netbox-community/netbox/issues/5149) - Add rack group field to device edit form
-* [#5164](https://github.com/netbox-community/netbox/issues/5164) - Show total rack count per rack group under site view
-* [#5171](https://github.com/netbox-community/netbox/issues/5171) - Introduce the `RQ_DEFAULT_TIMEOUT` configuration parameter
-
-### Bug Fixes
-
-* [#5050](https://github.com/netbox-community/netbox/issues/5050) - Fix potential failure on `0016_replicate_interfaces` schema migration from old release
-* [#5066](https://github.com/netbox-community/netbox/issues/5066) - Update `view_reportresult` to `view_report` permission
-* [#5075](https://github.com/netbox-community/netbox/issues/5075) - Include a VLAN membership view for VM interfaces
-* [#5105](https://github.com/netbox-community/netbox/issues/5105) - Validation should fail when reassigning a primary IP from device to VM
-* [#5109](https://github.com/netbox-community/netbox/issues/5109) - Fix representation of custom choice field values for webhook data
-* [#5108](https://github.com/netbox-community/netbox/issues/5108) - Fix execution of reports via CLI
-* [#5111](https://github.com/netbox-community/netbox/issues/5111) - Allow use of tuples when specifying ObjectVar `query_params`
-* [#5118](https://github.com/netbox-community/netbox/issues/5118) - Specifying an empty list of tags should clear assigned tags (REST API)
-* [#5133](https://github.com/netbox-community/netbox/issues/5133) - Fix disassociation of an IP address from a VM interface
-* [#5136](https://github.com/netbox-community/netbox/issues/5136) - Fix exception when bulk editing interface 802.1Q mode
-* [#5156](https://github.com/netbox-community/netbox/issues/5156) - Add missing "add" button to rack reservations list
-* [#5167](https://github.com/netbox-community/netbox/issues/5167) - Support filtering ObjectChanges by multiple users
-
----
-
-## v2.9.3 (2020-09-04)
-
-### Enhancements
-
-* [#4977](https://github.com/netbox-community/netbox/issues/4977) - Redirect authenticated users from login view
-* [#5048](https://github.com/netbox-community/netbox/issues/5048) - Show the device/VM name when editing a component
-* [#5072](https://github.com/netbox-community/netbox/issues/5072) - Add REST API filters for image attachments
-* [#5080](https://github.com/netbox-community/netbox/issues/5080) - Add 8P6C, 8P4C, 8P2C port types
-
-### Bug Fixes
-
-* [#5046](https://github.com/netbox-community/netbox/issues/5046) - Disabled plugin menu items are no longer clickable
-* [#5063](https://github.com/netbox-community/netbox/issues/5063) - Fix "add device" link in rack elevations for opposite side of half-depth devices
-* [#5074](https://github.com/netbox-community/netbox/issues/5074) - Fix inclusion of VC member interfaces when viewing VC master
-* [#5078](https://github.com/netbox-community/netbox/issues/5078) - Fix assignment of existing IP addresses to interfaces via web UI
-* [#5081](https://github.com/netbox-community/netbox/issues/5081) - Fix exception during webhook processing with custom select field
-* [#5085](https://github.com/netbox-community/netbox/issues/5085) - Fix ordering by assignment in IP addresses table
-* [#5087](https://github.com/netbox-community/netbox/issues/5087) - Restore label field when editing console server ports, power ports, and power outlets
-* [#5089](https://github.com/netbox-community/netbox/issues/5089) - Redirect to device view after editing component
-* [#5090](https://github.com/netbox-community/netbox/issues/5090) - Fix status display for console/power/interface connections
-* [#5091](https://github.com/netbox-community/netbox/issues/5091) - Avoid KeyError when handling invalid table preferences
-* [#5095](https://github.com/netbox-community/netbox/issues/5095) - Show assigned prefixes in VLANs list
-
----
-
-## v2.9.2 (2020-08-27)
-
-### Enhancements
-
-* [#5055](https://github.com/netbox-community/netbox/issues/5055) - Add tags column to device/VM component list tables
-* [#5056](https://github.com/netbox-community/netbox/issues/5056) - Add interface and parent columns to IP address list
-
-### Bug Fixes
-
-* [#4988](https://github.com/netbox-community/netbox/issues/4988) - Fix ordering of rack reservations with identical creation times
-* [#5002](https://github.com/netbox-community/netbox/issues/5002) - Correct OpenAPI definition for `available-prefixes` endpoint
-* [#5035](https://github.com/netbox-community/netbox/issues/5035) - Fix exception when modifying an IP address assigned to a VM
-* [#5038](https://github.com/netbox-community/netbox/issues/5038) - Fix validation of primary IPs assigned to virtual machines
-* [#5040](https://github.com/netbox-community/netbox/issues/5040) - Limit SLAAC status to IPv6 addresses
-* [#5041](https://github.com/netbox-community/netbox/issues/5041) - Fix form tabs when assigning an IP to a VM interface
-* [#5042](https://github.com/netbox-community/netbox/issues/5042) - Fix display of SLAAC label for IP addresses status
-* [#5045](https://github.com/netbox-community/netbox/issues/5045) - Allow assignment of interfaces to non-master VC peer LAG during import
-* [#5058](https://github.com/netbox-community/netbox/issues/5058) - Correct URL for front rack elevation images when using external storage
-* [#5059](https://github.com/netbox-community/netbox/issues/5059) - Fix inclusion of checkboxes for interfaces in virtual machine view
-* [#5060](https://github.com/netbox-community/netbox/issues/5060) - Fix validation when bulk-importing child devices
-* [#5061](https://github.com/netbox-community/netbox/issues/5061) - Allow adding/removing tags when bulk editing virtual machine interfaces
-
----
-
-## v2.9.1 (2020-08-22)
-
-### Enhancements
-
-* [#4540](https://github.com/netbox-community/netbox/issues/4540) - Add IP address status type for SLAAC
-* [#4814](https://github.com/netbox-community/netbox/issues/4814) - Allow nested LAG interfaces
-* [#4991](https://github.com/netbox-community/netbox/issues/4991) - Add Python and NetBox versions to error page
-* [#5033](https://github.com/netbox-community/netbox/issues/5033) - Support backward compatibility for `REMOTE_AUTH_BACKEND` configuration parameter
-
----
-
-## v2.9.0 (2020-08-21)
-
-**Note:** Redis 4.0 or later is required for this release.
-
-### New Features
-
-#### Object-Based Permissions ([#554](https://github.com/netbox-community/netbox/issues/554))
-
-NetBox v2.9 replaces Django's built-in permissions framework with one that supports object-based assignment of permissions using arbitrary constraints. When granting a user or group permission to perform a certain action on one or more types of objects, an administrator can optionally specify a set of constraints. The permission will apply only to objects which match the specified constraints. For example, assigning permission to modify devices with the constraint `{"tenant__group__name": "Customers"}` would allow the associated users/groups to perform an action only on devices assigned to a tenant belonging to the "Customers" group.
-
-#### Background Execution of Scripts & Reports ([#2006](https://github.com/netbox-community/netbox/issues/2006))
-
-When running a report or custom script, its execution is now queued for background processing and the user receives an immediate response indicating its status. This prevents long-running scripts from resulting in a timeout error. Once the execution has completed, the page will automatically refresh to display its results. Both scripts and reports now store their output in the new JobResult model. (The ReportResult model has been removed.)
-
-#### Named Virtual Chassis ([#2018](https://github.com/netbox-community/netbox/issues/2018))
-
-The VirtualChassis model now has a mandatory `name` field. Names are assigned to the virtual chassis itself rather than referencing the master VC member. Additionally, the designation of a master is now optional: a virtual chassis may have only non-master members.
-
-#### Changes to Tag Creation ([#3703](https://github.com/netbox-community/netbox/issues/3703))
-
-Tags are no longer created automatically: A tag must be created by a user before it can be applied to any object. Additionally, the REST API representation of assigned tags has been expanded to be consistent with other objects.
-
-#### Dedicated Model for VM Interfaces ([#4721](https://github.com/netbox-community/netbox/issues/4721))
-
-A new model has been introduced to represent virtual machine interfaces. Although this change is largely transparent to the end user, note that the IP address model no longer has a foreign key to the Interface model under the DCIM app. This has been replaced with a generic foreign key named `assigned_object`.
-
-#### REST API Endpoints for Users and Groups ([#4877](https://github.com/netbox-community/netbox/issues/4877))
-
-Two new REST API endpoints have been added to facilitate the retrieval and manipulation of users and groups:
-
-* `/api/users/groups/`
-* `/api/users/users/`
-
-### Enhancements
-
-* [#4615](https://github.com/netbox-community/netbox/issues/4615) - Add `label` field for all device components and component templates
-* [#4639](https://github.com/netbox-community/netbox/issues/4639) - Improve performance of web UI prefixes list
-* [#4742](https://github.com/netbox-community/netbox/issues/4742) - Add tagging for cables, power panels, and rack reservations
-* [#4788](https://github.com/netbox-community/netbox/issues/4788) - Add dedicated views for all device components
-* [#4792](https://github.com/netbox-community/netbox/issues/4792) - Add bulk rename capability for console and power ports
-* [#4793](https://github.com/netbox-community/netbox/issues/4793) - Add `description` field to device component templates
-* [#4795](https://github.com/netbox-community/netbox/issues/4795) - Add bulk disconnect capability for console and power ports
-* [#4806](https://github.com/netbox-community/netbox/issues/4806) - Add a `url` field to all API serializers
-* [#4807](https://github.com/netbox-community/netbox/issues/4807) - Add bulk edit ability for device bay templates
-* [#4817](https://github.com/netbox-community/netbox/issues/4817) - Standardize device/VM component `name` field to 64 characters
-* [#4837](https://github.com/netbox-community/netbox/issues/4837) - Use dynamic form widget for relationships to MPTT objects (e.g. regions)
-* [#4840](https://github.com/netbox-community/netbox/issues/4840) - Enable change logging for config contexts
-* [#4885](https://github.com/netbox-community/netbox/issues/4885) - Add MultiChoiceVar for custom scripts
-* [#4940](https://github.com/netbox-community/netbox/issues/4940) - Add an `occupied` field to rack unit representations for rack elevation views
-* [#4945](https://github.com/netbox-community/netbox/issues/4945) - Add a user-friendly 403 error page
-* [#4969](https://github.com/netbox-community/netbox/issues/4969) - Replace secret role user/group assignment with object permissions
-* [#4982](https://github.com/netbox-community/netbox/issues/4982) - Extended ObjectVar to allow filtering API query
-* [#4994](https://github.com/netbox-community/netbox/issues/4994) - Add `cable` attribute to PowerFeed API serializer
-* [#4997](https://github.com/netbox-community/netbox/issues/4997) - The browsable API now lists available endpoints alphabetically
-* [#5024](https://github.com/netbox-community/netbox/issues/5024) - List available options for choice fields within CSV import forms
-
-### Configuration Changes
-
-* If using NetBox's built-in remote authentication backend, update `REMOTE_AUTH_BACKEND` to `'netbox.authentication.RemoteUserBackend'`, as the authentication class has moved.
-* If using LDAP authentication, set `REMOTE_AUTH_BACKEND` to `'netbox.authentication.LDAPBackend'`. (LDAP configuration parameters in `ldap_config.py` remain unchanged.)
-* `REMOTE_AUTH_DEFAULT_PERMISSIONS` now takes a dictionary rather than a list. This is a mapping of permission names to a dictionary of constraining attributes, or `None`. For example, `['dcim.add_site', 'dcim.change_site']` would become `{'dcim.add_site': None, 'dcim.change_site': None}`.
-* Backward compatibility for the old `webhooks` Redis queue name has been dropped. Ensure that your `REDIS` configuration parameter specifies both the `tasks` and `caching` databases.
-
-### REST API Changes
-
-* Added new endpoints for users, groups, and permissions under `/api/users/`.
-* A `url` field is now included on all object representations, identifying the unique REST API URL for each object.
-* The `tags` field of an object now includes a more complete representation of each tag, rather than just its name.
-* The assignment of tags to an object is now achieved in the same manner as specifying any other related device. The `tags` field accepts a list of JSON objects each matching a desired tag. (Alternatively, a list of numeric primary keys corresponding to tags may be passed instead.) For example:
-
-```json
-"tags": [
-  {"name": "First Tag"},
-  {"name": "Second Tag"}
-]
-```
-
-* Legacy numeric values for choice fields are no longer conveyed or accepted.
-* circuits.CircuitTermination: Added `cable` field
-* dcim.Cable: Added `tags` field
-* dcim.ConsolePort: Added `label` field
-* dcim.ConsolePortTemplate: Added `description` and `label` fields
-* dcim.ConsoleServerPort: Added `label` field
-* dcim.ConsoleServerPortTemplate: Added `description` and `label` fields
-* dcim.DeviceBay: Added `label` field
-* dcim.DeviceBayTemplate: Added `description` and `label` fields
-* dcim.FrontPort: Added `label` field
-* dcim.FrontPortTemplate: Added `description` and `label` fields
-* dcim.Interface: Added `label` field
-* dcim.InterfaceTemplate: Added `description` and `label` fields
-* dcim.PowerFeed: Added `cable` field
-* dcim.PowerPanel: Added `tags` field
-* dcim.PowerPort: Added ``label` field
-* dcim.PowerPortTemplate: Added `description` and `label` fields
-* dcim.PowerOutlet: Added `label` field
-* dcim.PowerOutletTemplate: Added `description` and `label` fields
-* dcim.Rack: Added an `occupied` field to rack unit representations for rack elevation views
-* dcim.RackGroup: Added a `_depth` attribute indicating an object's position in the tree.
-* dcim.RackReservation: Added `tags` field
-* dcim.RearPort: Added `label` field
-* dcim.RearPortTemplate: Added `description` and `label` fields
-* dcim.Region: Added a `_depth` attribute indicating an object's position in the tree.
-* dcim.VirtualChassis: Added `name` field (required)
-* extras.ConfigContext: Added `created` and `last_updated` fields
-* extras.JobResult: Added the `/api/extras/job-results/` endpoint
-* extras.Report: The `failed` field has been removed. The `completed` (boolean) and `status` (string) fields have been introduced to convey the status of a report's most recent execution. Additionally, the `result` field now conveys the nested representation of a JobResult.
-* extras.Script: Added `module` and `result` fields. The `result` field now conveys the nested representation of a JobResult.
-* extras.Tag: The count of `tagged_items` is no longer included when viewing the tags list when `brief` is passed.
-* ipam.IPAddress: Removed `interface` field; replaced with `assigned_object` generic foreign key. This may represent either a device interface or a virtual machine interface. Assign an object by setting `assigned_object_type` and `assigned_object_id`.
-* ipam.VRF: Added `display_name`
-* tenancy.TenantGroup: Added a `_depth` attribute indicating an object's position in the tree.
-* users.ObjectPermissions: Added the `/api/users/permissions/` endpoint
-* virtualization.VMInterface: Removed `type` field (VM interfaces have no type)
-
-### Other Changes
-
-* A new model, `VMInterface` has been introduced to represent interfaces assigned to VirtualMachine instances. Previously, these interfaces utilized the DCIM model `Interface`. Instances will be replicated automatically upon upgrade, however any custom code which references or manipulates virtual machine interfaces will need to be updated accordingly.
-* The `secrets.activate_userkey` permission no longer exists. Instead, `secrets.change_userkey` is checked to determine whether a user has the ability to activate a UserKey.
-* The `users.delete_token` permission is no longer enforced. All users are permitted to delete their own API tokens.
-* Dropped backward compatibility for the `webhooks` Redis queue configuration (use `tasks` instead).
-* Dropped backward compatibility for the `/admin/webhook-backend-status` URL (moved to `/admin/background-tasks/`).
-* Virtual chassis are now created by navigating to `/dcim/virtual-chassis/add/` rather than via the devices list.
-* A name is required when creating a virtual chassis.

+ 38 - 0
docs/release-notes/version-4.6.md

@@ -1,5 +1,43 @@
 # NetBox v4.6
 
+## v4.6.4 (2026-06-30)
+
+### Enhancements
+
+* [#21710](https://github.com/netbox-community/netbox/issues/21710) - Render JSON schema `enum` options as a dropdown selection in module and device profile attribute forms
+* [#22174](https://github.com/netbox-community/netbox/issues/22174) - Include the `dns_name` of primary & out-of-band IP addresses in event payloads
+* [#22279](https://github.com/netbox-community/netbox/issues/22279) - Add a 1C8P:8C1P breakout cable profile
+* [#22548](https://github.com/netbox-community/netbox/issues/22548) - Improve the styling of action buttons in the navigation sidebar
+
+### Performance Improvements
+
+* [#22169](https://github.com/netbox-community/netbox/issues/22169) - Improve performance of the image attachments view when using S3 storage
+* [#22442](https://github.com/netbox-community/netbox/issues/22442) - Avoid repeated serializer instantiation in `GFKSerializerField`
+* [#22526](https://github.com/netbox-community/netbox/issues/22526) - Chunk bulk updates to custom field data to better handle a large number of records
+
+### Bug Fixes
+
+* [#21310](https://github.com/netbox-community/netbox/issues/21310) - Fix LDAP group lookup failure when a returned row contains a null value
+* [#22439](https://github.com/netbox-community/netbox/issues/22439) - Enforce object-level permissions on custom links rendered via the `custom_links` template tag
+* [#22440](https://github.com/netbox-community/netbox/issues/22440) - Remove errant `changelog` relation from GraphQL schema
+* [#22480](https://github.com/netbox-community/netbox/issues/22480) - Restore inline browser display of device front/rear images instead of forcing a download
+* [#22489](https://github.com/netbox-community/netbox/issues/22489) - Update the cached virtual chassis name on member devices in the search index when a virtual chassis is renamed
+* [#22501](https://github.com/netbox-community/netbox/issues/22501) - Return JSON rather than an HTML error page for GraphQL API exceptions
+* [#22507](https://github.com/netbox-community/netbox/issues/22507) - Also check `is_active` in the superuser bypass for `restrict()` and `IsSuperuser`
+* [#22543](https://github.com/netbox-community/netbox/issues/22543) - Prevent deletion of an existing custom script's file when re-uploading a same-named script via the REST API
+* [#22561](https://github.com/netbox-community/netbox/issues/22561) - Fix `AttributeError` when importing IP addresses with `is_primary`/`is_oob` set but no device assigned
+
+### Accessibility
+
+* [#22527](https://github.com/netbox-community/netbox/issues/22527) - Announce quick search results to screen readers
+* [#22528](https://github.com/netbox-community/netbox/issues/22528) - Make the Results/Filters tabs keyboard-operable
+* [#22529](https://github.com/netbox-community/netbox/issues/22529) - Allow the left sidebar accordion to be toggled with the spacebar
+* [#22530](https://github.com/netbox-community/netbox/issues/22530) - Remove hidden `<select>` inputs from the accessibility tree
+* [#22531](https://github.com/netbox-community/netbox/issues/22531) - Associate a label with the "Saved Filter" combobox for screen readers
+* [#22532](https://github.com/netbox-community/netbox/issues/22532) - Provide an accessible name for the empty checkbox column header cell in object tables
+
+---
+
 ## v4.6.3 (2026-06-16)
 
 ### Enhancements

+ 1 - 12
mkdocs.yml

@@ -171,6 +171,7 @@ nav:
             - Okta: 'administration/authentication/okta.md'
         - Permissions: 'administration/permissions.md'
         - Error Reporting: 'administration/error-reporting.md'
+        - Management Commands: 'administration/management-commands.md'
         - Replicating NetBox: 'administration/replicating-netbox.md'
         - NetBox Shell: 'administration/netbox-shell.md'
     - Data Model:
@@ -349,15 +350,3 @@ nav:
         - Version 3.2: 'release-notes/version-3.2.md'
         - Version 3.1: 'release-notes/version-3.1.md'
         - Version 3.0: 'release-notes/version-3.0.md'
-        - Version 2.11: 'release-notes/version-2.11.md'
-        - Version 2.10: 'release-notes/version-2.10.md'
-        - Version 2.9: 'release-notes/version-2.9.md'
-        - Version 2.8: 'release-notes/version-2.8.md'
-        - Version 2.7: 'release-notes/version-2.7.md'
-        - Version 2.6: 'release-notes/version-2.6.md'
-        - Version 2.5: 'release-notes/version-2.5.md'
-        - Version 2.4: 'release-notes/version-2.4.md'
-        - Version 2.3: 'release-notes/version-2.3.md'
-        - Version 2.2: 'release-notes/version-2.2.md'
-        - Version 2.1: 'release-notes/version-2.1.md'
-        - Version 2.0: 'release-notes/version-2.0.md'

+ 0 - 9
netbox/core/graphql/filter_mixins.py

@@ -1,13 +1,8 @@
 from dataclasses import dataclass
-from typing import TYPE_CHECKING, Annotated
 
-import strawberry
 import strawberry_django
 from strawberry_django import DatetimeFilterLookup
 
-if TYPE_CHECKING:
-    from .filters import *
-
 __all__ = (
     'ChangeLoggingMixin',
 )
@@ -15,9 +10,5 @@ __all__ = (
 
 @dataclass
 class ChangeLoggingMixin:
-    # TODO: "changelog" is not a valid field name; needs to be updated for ObjectChange
-    changelog: Annotated['ObjectChangeFilter', strawberry.lazy('core.graphql.filters')] | None = (
-        strawberry_django.filter_field()
-    )
     created: DatetimeFilterLookup | None = strawberry_django.filter_field()
     last_updated: DatetimeFilterLookup | None = strawberry_django.filter_field()

+ 22 - 7
netbox/dcim/api/serializers_/devices.py

@@ -61,25 +61,25 @@ class DeviceSerializer(PrimaryModelSerializer):
         nested=True,
         read_only=True,
         allow_null=True,
-        fields=[*IPAddressSerializer.Meta.brief_fields, 'nat_inside', 'nat_outside'],
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
     )
     primary_ip4 = IPAddressSerializer(
         nested=True,
         required=False,
         allow_null=True,
-        fields=[*IPAddressSerializer.Meta.brief_fields, 'nat_inside', 'nat_outside'],
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
     )
     primary_ip6 = IPAddressSerializer(
         nested=True,
         required=False,
         allow_null=True,
-        fields=[*IPAddressSerializer.Meta.brief_fields, 'nat_inside', 'nat_outside'],
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
     )
     oob_ip = IPAddressSerializer(
         nested=True,
         required=False,
         allow_null=True,
-        fields=[*IPAddressSerializer.Meta.brief_fields, 'nat_inside', 'nat_outside'],
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
     )
     parent_device = serializers.SerializerMethodField()
     cluster = ClusterSerializer(nested=True, required=False, allow_null=True)
@@ -133,9 +133,24 @@ class VirtualDeviceContextSerializer(PrimaryModelSerializer):
     device = DeviceSerializer(nested=True)
     identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None)
-    primary_ip = IPAddressSerializer(nested=True, read_only=True, allow_null=True)
-    primary_ip4 = IPAddressSerializer(nested=True, required=False, allow_null=True)
-    primary_ip6 = IPAddressSerializer(nested=True, required=False, allow_null=True)
+    primary_ip = IPAddressSerializer(
+        nested=True,
+        read_only=True,
+        allow_null=True,
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
+    )
+    primary_ip4 = IPAddressSerializer(
+        nested=True,
+        required=False,
+        allow_null=True,
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
+    )
+    primary_ip6 = IPAddressSerializer(
+        nested=True,
+        required=False,
+        allow_null=True,
+        fields=[*IPAddressSerializer.Meta.brief_fields, 'dns_name', 'nat_inside', 'nat_outside'],
+    )
     status = ChoiceField(choices=VirtualDeviceContextStatusChoices)
 
     # Related object counts

+ 33 - 0
netbox/dcim/cable_profiles.py

@@ -409,6 +409,39 @@ class Breakout1C6Px6C1PCableProfile(BaseCableProfile):
     }
 
 
+class Breakout1C8Px8C1PCableProfile(BaseCableProfile):
+    a_connectors = {
+        1: 8,
+    }
+    b_connectors = {
+        1: 1,
+        2: 1,
+        3: 1,
+        4: 1,
+        5: 1,
+        6: 1,
+        7: 1,
+        8: 1,
+    }
+    _mapping = {
+        (1, 1): (1, 1),
+        (1, 2): (2, 1),
+        (1, 3): (3, 1),
+        (1, 4): (4, 1),
+        (1, 5): (5, 1),
+        (1, 6): (6, 1),
+        (1, 7): (7, 1),
+        (1, 8): (8, 1),
+        (2, 1): (1, 2),
+        (3, 1): (1, 3),
+        (4, 1): (1, 4),
+        (5, 1): (1, 5),
+        (6, 1): (1, 6),
+        (7, 1): (1, 7),
+        (8, 1): (1, 8),
+    }
+
+
 class Trunk2C4PShuffleCableProfile(BaseCableProfile):
     a_connectors = {
         1: 4,

+ 2 - 0
netbox/dcim/choices.py

@@ -1787,6 +1787,7 @@ class CableProfileChoices(ChoiceSet):
     BREAKOUT_1C2P_2C1P = 'breakout-1c2p-2c1p'
     BREAKOUT_1C4P_4C1P = 'breakout-1c4p-4c1p'
     BREAKOUT_1C6P_6C1P = 'breakout-1c6p-6c1p'
+    BREAKOUT_1C8P_8C1P = 'breakout-1c8p-8c1p'
     BREAKOUT_2C4P_8C1P_SHUFFLE = 'breakout-2c4p-8c1p-shuffle'
 
     CHOICES = (
@@ -1827,6 +1828,7 @@ class CableProfileChoices(ChoiceSet):
                 (BREAKOUT_1C2P_2C1P, _('1C2P:2C1P breakout')),
                 (BREAKOUT_1C4P_4C1P, _('1C4P:4C1P breakout')),
                 (BREAKOUT_1C6P_6C1P, _('1C6P:6C1P breakout')),
+                (BREAKOUT_1C8P_8C1P, _('1C8P:8C1P breakout')),
                 (BREAKOUT_2C4P_8C1P_SHUFFLE, _('2C4P:8C1P breakout (shuffle)')),
             ),
         ),

+ 1 - 0
netbox/dcim/models/cables.py

@@ -207,6 +207,7 @@ class Cable(PrimaryModel):
             CableProfileChoices.BREAKOUT_1C2P_2C1P: cable_profiles.Breakout1C2Px2C1PCableProfile,
             CableProfileChoices.BREAKOUT_1C4P_4C1P: cable_profiles.Breakout1C4Px4C1PCableProfile,
             CableProfileChoices.BREAKOUT_1C6P_6C1P: cable_profiles.Breakout1C6Px6C1PCableProfile,
+            CableProfileChoices.BREAKOUT_1C8P_8C1P: cable_profiles.Breakout1C8Px8C1PCableProfile,
             CableProfileChoices.BREAKOUT_2C4P_8C1P_SHUFFLE: cable_profiles.Breakout2C4Px8C1PShuffleCableProfile,
         }.get(self.profile)
 

+ 6 - 1
netbox/dcim/models/modules.py

@@ -1,3 +1,5 @@
+from collections.abc import Iterable, Mapping
+
 import jsonschema
 import yaml
 from django.core.exceptions import ValidationError
@@ -169,7 +171,10 @@ class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
         attrs = {}
         for name, options in self.profile.schema.get('properties', {}).items():
             key = options.get('title', title(name))
-            attrs[key] = self.attribute_data.get(name)
+            value = self.attribute_data.get(name)
+            if isinstance(value, Iterable) and not isinstance(value, (str, bytes, Mapping)):
+                value = ', '.join(str(v) for v in value)
+            attrs[key] = value
         return dict(sorted(attrs.items()))
 
     def clean(self):

+ 20 - 0
netbox/dcim/signals.py

@@ -5,6 +5,7 @@ from django.db.models.signals import post_delete, post_save
 from django.dispatch import receiver
 
 from dcim.choices import CableEndChoices, LinkStatusChoices
+from netbox.search.backends import search_backend
 from virtualization.models import VMInterface
 
 from .models import (
@@ -21,6 +22,7 @@ from .models import (
     VirtualChassis,
 )
 from .models.cables import trace_paths
+from .search import DeviceIndex
 from .utils import create_cablepaths, rebuild_paths
 
 #
@@ -70,6 +72,24 @@ def assign_virtualchassis_master(instance, created, **kwargs):
         master.save()
 
 
+@receiver(post_save, sender=VirtualChassis)
+def update_virtualchassis_member_search_cache(instance, created, raw=False, update_fields=None, **kwargs):
+    """
+    Refresh the search cache for member Devices when a VirtualChassis is renamed. DeviceIndex caches
+    virtual_chassis as its string value, so a rename would otherwise leave stale CachedValue entries.
+    """
+    if raw or created:
+        return
+    # The VC name is the only VC attribute cached on member Devices; skip saves that can't change it.
+    if update_fields is not None and 'name' not in update_fields:
+        return
+    search_backend.cache(
+        Device.objects.filter(virtual_chassis=instance).select_related('virtual_chassis'),
+        indexer=DeviceIndex,
+        remove_existing=True
+    )
+
+
 #
 # Cables
 #

+ 1 - 1
netbox/dcim/tests/query_counts.json

@@ -42,7 +42,7 @@
   "modulebay:list_objects_with_permission": 21,
   "modulebaytemplate:api_list_objects": 11,
   "moduletype:api_list_objects": 14,
-  "moduletype:list_objects_with_permission": 21,
+  "moduletype:list_objects_with_permission": 22,
   "moduletypeprofile:api_list_objects": 13,
   "moduletypeprofile:list_objects_with_permission": 20,
   "platform:api_list_objects": 13,

+ 122 - 1
netbox/dcim/tests/test_api.py

@@ -12,7 +12,7 @@ from dcim.constants import *
 from dcim.models import *
 from extras.models import ConfigTemplate, Tag
 from ipam.choices import VLANQinQRoleChoices
-from ipam.models import ASN, RIR, VLAN, VRF
+from ipam.models import ASN, RIR, VLAN, VRF, IPAddress
 from netbox.api.serializers import GenericObjectSerializer
 from tenancy.models import Tenant
 from users.constants import TOKEN_PREFIX
@@ -2075,6 +2075,58 @@ class DeviceTestCase(APIViewTestCases.APIViewTestCase):
         self.assertEqual(response.data['oob_ip']['nat_inside']['address'], str(real_ip.address))
         self.assertEqual(response.data['oob_ip']['nat_outside'], [])
 
+    def test_get_object_includes_dns_name_on_primary_ip(self):
+        device = create_test_device('dns-device')
+        interfaces = (
+            Interface.objects.create(device=device, name='eth0', type='other'),
+            Interface.objects.create(device=device, name='eth1', type='other'),
+        )
+
+        ip4 = IPAddress(address='192.0.2.10/32', dns_name='device4.example.com')
+        ip4.assigned_object = interfaces[0]
+        ip4.save()
+        ip6 = IPAddress(address='2001:db8::10/128', dns_name='device6.example.com')
+        ip6.assigned_object = interfaces[1]
+        ip6.save()
+
+        device.primary_ip4 = ip4
+        device.primary_ip6 = ip6
+        device.save()
+
+        self.add_permissions('dcim.view_device', 'ipam.view_ipaddress')
+        response = self.client.get(
+            f'{self._get_detail_url(device)}?exclude=config_context',
+            **self.header,
+        )
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+
+        self.assertEqual(response.data['primary_ip4']['dns_name'], 'device4.example.com')
+        self.assertEqual(response.data['primary_ip6']['dns_name'], 'device6.example.com')
+        self.assertIn(
+            response.data['primary_ip']['dns_name'],
+            ('device4.example.com', 'device6.example.com'),
+        )
+
+    def test_get_object_includes_dns_name_on_oob_ip(self):
+        device = create_test_device('dns-oob-device')
+        interface = Interface.objects.create(device=device, name='oob0', type='other')
+
+        ip = IPAddress(address='192.0.2.20/32', dns_name='oob.example.com')
+        ip.assigned_object = interface
+        ip.save()
+
+        device.oob_ip = ip
+        device.save()
+
+        self.add_permissions('dcim.view_device', 'ipam.view_ipaddress')
+        response = self.client.get(
+            f'{self._get_detail_url(device)}?exclude=config_context',
+            **self.header,
+        )
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+
+        self.assertEqual(response.data['oob_ip']['dns_name'], 'oob.example.com')
+
     def test_render_config_with_config_template_id(self):
         default_template = ConfigTemplate.objects.create(
             name='Default Template',
@@ -3863,6 +3915,75 @@ class VirtualDeviceContextTestCase(APIViewTestCases.APIViewTestCase):
             },
         ]
 
+    def test_get_object_includes_nat_on_primary_ip(self):
+        device = create_test_device('vdc-nat-device')
+        interfaces = (
+            Interface.objects.create(device=device, name='eth0', type='other'),
+            Interface.objects.create(device=device, name='eth1', type='other'),
+        )
+
+        real_ip4, nat_ip4 = create_test_nat_ip_pair(
+            real_address='10.0.2.10/32',
+            nat_address='198.51.100.30/32',
+            inside_interface=interfaces[0],
+        )
+        real_ip6, nat_ip6 = create_test_nat_ip_pair(
+            real_address='2001:db8:2::10/128',
+            nat_address='2001:db8:2::20/128',
+            inside_interface=interfaces[1],
+        )
+
+        vdc = VirtualDeviceContext.objects.create(
+            name='VDC NAT', identifier=98, device=device, status='active'
+        )
+        vdc.primary_ip4 = nat_ip4
+        vdc.primary_ip6 = real_ip6
+        vdc.save()
+
+        self.add_permissions('dcim.view_virtualdevicecontext', 'ipam.view_ipaddress')
+        response = self.client.get(self._get_detail_url(vdc), **self.header)
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+
+        self.assertEqual(response.data['primary_ip4']['nat_inside']['address'], str(real_ip4.address))
+        self.assertEqual(response.data['primary_ip4']['nat_outside'], [])
+        self.assertIsNone(response.data['primary_ip6']['nat_inside'])
+        self.assertCountEqual(
+            [ip['address'] for ip in response.data['primary_ip6']['nat_outside']],
+            [str(nat_ip6.address)],
+        )
+
+    def test_get_object_includes_dns_name_on_primary_ip(self):
+        device = create_test_device('vdc-dns-device')
+        interfaces = (
+            Interface.objects.create(device=device, name='eth0', type='other'),
+            Interface.objects.create(device=device, name='eth1', type='other'),
+        )
+
+        ip4 = IPAddress(address='192.0.2.30/32', dns_name='vdc4.example.com')
+        ip4.assigned_object = interfaces[0]
+        ip4.save()
+        ip6 = IPAddress(address='2001:db8::30/128', dns_name='vdc6.example.com')
+        ip6.assigned_object = interfaces[1]
+        ip6.save()
+
+        vdc = VirtualDeviceContext.objects.create(
+            name='VDC DNS', identifier=99, device=device, status='active'
+        )
+        vdc.primary_ip4 = ip4
+        vdc.primary_ip6 = ip6
+        vdc.save()
+
+        self.add_permissions('dcim.view_virtualdevicecontext', 'ipam.view_ipaddress')
+        response = self.client.get(self._get_detail_url(vdc), **self.header)
+        self.assertHttpStatus(response, status.HTTP_200_OK)
+
+        self.assertEqual(response.data['primary_ip4']['dns_name'], 'vdc4.example.com')
+        self.assertEqual(response.data['primary_ip6']['dns_name'], 'vdc6.example.com')
+        self.assertIn(
+            response.data['primary_ip']['dns_name'],
+            ('vdc4.example.com', 'vdc6.example.com'),
+        )
+
 
 class MACAddressTestCase(APIViewTestCases.APIViewTestCase):
     model = MACAddress

+ 53 - 0
netbox/dcim/tests/test_cable_profiles.py

@@ -2,6 +2,7 @@ from django.test import tag
 
 from dcim.cable_profiles import (
     Breakout1C4Px4C1PCableProfile,
+    Breakout1C8Px8C1PCableProfile,
     Single1C1PCableProfile,
     Single1C4PCableProfile,
     Trunk2C2PCableProfile,
@@ -74,6 +75,32 @@ class CableProfileLinkPeerTestCase(BaseCablePathTestCase):
         for interface in interfaces[2:4] + interfaces[6:8]:
             self.assertEqual(interface.link_peers, [rear_ports[1]])
 
+    def test_breakout_1c8p_8c1p_link_peers(self):
+        """
+        Link peers for a 1C8P:8C1P breakout map the single A-side connector's
+        eight positions to the eight B-side connectors, and each back to it.
+        """
+        a_interface = Interface.objects.create(device=self.device, name='Interface A')
+        b_interfaces = [
+            Interface.objects.create(device=self.device, name=f'Interface B{i}') for i in range(1, 9)
+        ]
+
+        cable = Cable(
+            profile=CableProfileChoices.BREAKOUT_1C8P_8C1P,
+            a_terminations=[a_interface],
+            b_terminations=b_interfaces,
+        )
+        cable.clean()
+        cable.save()
+
+        a_interface.refresh_from_db()
+        for iface in b_interfaces:
+            iface.refresh_from_db()
+
+        self.assertEqual(a_interface.link_peers, b_interfaces)
+        for iface in b_interfaces:
+            self.assertEqual(iface.link_peers, [a_interface])
+
 
 class CableProfilePeerTerminationTestCase(BaseCablePathTestCase):
     """
@@ -228,6 +255,32 @@ class CableProfilePeerTerminationTestCase(BaseCablePathTestCase):
         b_pairs = [(iface, 1) for iface in self.interfaces[9:13]]
         self._assert_batch_matches_singular(profile, b_pairs)
 
+    def test_breakout_1c8p_profile(self):
+        """
+        Batch resolution on a 1C8P:8C1P breakout maps one A-side connector's
+        eight positions to eight B-side connectors.
+        """
+        cable = Cable(
+            profile=CableProfileChoices.BREAKOUT_1C8P_8C1P,
+            a_terminations=[self.interfaces[0]],
+            b_terminations=self.interfaces[1:9],
+        )
+        cable.clean()
+        cable.save()
+
+        self.interfaces[0].refresh_from_db()
+        for iface in self.interfaces[1:9]:
+            iface.refresh_from_db()
+        profile = Breakout1C8Px8C1PCableProfile()
+
+        # A→B direction (one connector, 8 positions → 8 connectors)
+        a_pairs = [(self.interfaces[0], pos) for pos in self.interfaces[0].cable_positions]
+        self._assert_batch_matches_singular(profile, a_pairs)
+
+        # B→A direction (8 connectors, 1 position each → one connector)
+        b_pairs = [(iface, 1) for iface in self.interfaces[1:9]]
+        self._assert_batch_matches_singular(profile, b_pairs)
+
     def test_multi_position_single_termination(self):
         """
         When a single-connector multi-position profile has only one termination

+ 48 - 0
netbox/dcim/tests/test_forms.py

@@ -1,3 +1,6 @@
+from unittest.mock import patch
+
+from django import forms
 from django.test import TestCase
 
 from dcim.choices import (
@@ -177,6 +180,51 @@ class DeviceTestCase(TestCase):
         self.assertIn('position', form.errors)
 
 
+class ModuleTypeFormTestCase(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+        cls.profile = ModuleTypeProfile.objects.create(
+            name='Module Type Profile 1',
+            schema={
+                'properties': {
+                    'media': {
+                        'title': 'Media',
+                        'type': 'array',
+                        'items': {
+                            'type': 'string',
+                            'enum': ['copper', 'sfp', 'qsfp28'],
+                        },
+                    },
+                },
+            },
+        )
+
+    def test_enum_array_attribute_uses_multiselect_field(self):
+        form = ModuleTypeForm(data={
+            'manufacturer': self.manufacturer.pk,
+            'model': 'Module Type 1',
+            'profile': self.profile.pk,
+            'attr_media': ['copper', 'qsfp28'],
+        })
+
+        self.assertIsInstance(form.fields['attr_media'], forms.MultipleChoiceField)
+        self.assertEqual(
+            list(form.fields['attr_media'].choices),
+            [
+                ('copper', 'copper'),
+                ('sfp', 'sfp'),
+                ('qsfp28', 'qsfp28'),
+            ],
+        )
+        with patch('utilities.forms.fields.dynamic.get_action_url', return_value='/'):
+            self.assertTrue(form.is_valid(), form.errors)
+
+            module_type = form.save()
+            self.assertEqual(module_type.attribute_data, {'media': ['copper', 'qsfp28']})
+
+
 class VCPositionTokenFormTestCase(TestCase):
 
     @classmethod

+ 39 - 0
netbox/dcim/tests/test_models.py

@@ -179,6 +179,45 @@ class ModuleTypeTestCase(TestCase):
         module_type.refresh_from_db()
         self.assertEqual(module_type.interface_template_count, 1)
 
+    def test_attributes(self):
+        """
+        ModuleType.attributes should normalize iterable values into strings for presentation.
+        """
+        manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+        profile = ModuleTypeProfile.objects.create(
+            name='Module Type Profile 1',
+            schema={
+                'properties': {
+                    'media': {
+                        'title': 'Media',
+                        'type': 'array',
+                        'items': {'type': 'string'},
+                    },
+                    'enabled': {
+                        'title': 'Enabled',
+                        'type': 'boolean',
+                    },
+                },
+            },
+        )
+        module_type = ModuleType.objects.create(
+            manufacturer=manufacturer,
+            model='Module Type 1',
+            profile=profile,
+            attribute_data={
+                'media': ['sfp', 'qsfp28'],
+                'enabled': True,
+            },
+        )
+
+        self.assertEqual(
+            module_type.attributes,
+            {
+                'Enabled': True,
+                'Media': 'sfp, qsfp28',
+            },
+        )
+
 
 class RackTypeTestCase(TestCase):
 

+ 66 - 0
netbox/dcim/tests/test_search.py

@@ -0,0 +1,66 @@
+from django.test import TestCase
+
+from core.models import ObjectType
+from dcim.models import Device, VirtualChassis
+from extras.models import CachedValue
+from utilities.testing import create_test_device
+
+
+class VirtualChassisSearchCacheTestCase(TestCase):
+
+    def setUp(self):
+        self.vc = VirtualChassis.objects.create(name='VC1')
+        self.device = create_test_device('Switch-1', virtual_chassis=self.vc, vc_position=1)
+        self.object_type = ObjectType.objects.get_for_model(Device)
+
+    def test_renaming_virtual_chassis_refreshes_member_search_cache(self):
+        """
+        Renaming a VirtualChassis updates the cached virtual_chassis value for its member Devices.
+        """
+        # The member device is initially cached under the original VC name
+        self.assertTrue(
+            CachedValue.objects.filter(
+                object_type=self.object_type,
+                object_id=self.device.pk,
+                field='virtual_chassis',
+                value='VC1',
+            ).exists()
+        )
+
+        # Rename the VirtualChassis
+        self.vc.name = 'VC-test'
+        self.vc.save()
+
+        # The stale entry is gone and a fresh one reflects the new name
+        self.assertFalse(
+            CachedValue.objects.filter(
+                object_type=self.object_type,
+                object_id=self.device.pk,
+                field='virtual_chassis',
+                value='VC1',
+            ).exists()
+        )
+        self.assertTrue(
+            CachedValue.objects.filter(
+                object_type=self.object_type,
+                object_id=self.device.pk,
+                field='virtual_chassis',
+                value='VC-test',
+            ).exists()
+        )
+
+    def test_updating_virtual_chassis_without_name_change_keeps_member_cache(self):
+        """
+        A targeted save excluding 'name' leaves the member Device search cache untouched.
+        """
+        self.vc.domain = 'example'
+        self.vc.save(update_fields=['domain'])
+
+        self.assertTrue(
+            CachedValue.objects.filter(
+                object_type=self.object_type,
+                object_id=self.device.pk,
+                field='virtual_chassis',
+                value='VC1',
+            ).exists()
+        )

+ 68 - 3
netbox/dcim/tests/test_views.py

@@ -1226,6 +1226,19 @@ console-ports:
 class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
     model = ModuleType
 
+    SCHEMA = {
+        'properties': {
+            'media': {
+                'title': 'Media',
+                'type': 'array',
+                'items': {
+                    'type': 'string',
+                    'enum': ['copper', 'sfp', 'qsfp28'],
+                },
+            },
+        },
+    }
+
     @classmethod
     def setUpTestData(cls):
 
@@ -1235,8 +1248,15 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         )
         Manufacturer.objects.bulk_create(manufacturers)
 
+        profile = ModuleTypeProfile.objects.create(name='Module Type Profile 1', schema=cls.SCHEMA)
+
         module_types = ModuleType.objects.bulk_create([
-            ModuleType(model='Module Type 1', manufacturer=manufacturers[0]),
+            ModuleType(
+                model='Module Type 1',
+                manufacturer=manufacturers[0],
+                profile=profile,
+                attribute_data={'media': ['copper', 'qsfp28']},
+            ),
             ModuleType(model='Module Type 2', manufacturer=manufacturers[0]),
             ModuleType(model='Module Type 3', manufacturer=manufacturers[0]),
         ])
@@ -1319,6 +1339,19 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
 
         super().test_bulk_import_objects_with_constrained_permission()
 
+    @tag('regression')
+    def test_get_object_renders_profile_attribute_lists(self):
+        self.add_permissions(
+            'dcim.view_moduletype',
+            'dcim.view_moduletypeprofile',
+        )
+        moduletype = ModuleType.objects.first()
+        response = self.client.get(moduletype.get_absolute_url())
+
+        self.assertHttpStatus(response, 200)
+        self.assertContains(response, 'Media')
+        self.assertContains(response, 'copper, qsfp28')
+
     def test_moduletype_consoleports(self):
         self.add_permissions('dcim.view_moduletype', 'dcim.view_consoleporttemplate')
         moduletype = ModuleType.objects.first()
@@ -2558,14 +2591,33 @@ class ModuleTestCase(
     @classmethod
     def setUpTestData(cls):
         manufacturer = Manufacturer.objects.create(name='Generic', slug='generic')
-        module_type_profile = ModuleTypeProfile.objects.create(name='Module Type Profile 1')
+        module_type_profile = ModuleTypeProfile.objects.create(
+            name='Module Type Profile 1',
+            schema={
+                'properties': {
+                    'media': {
+                        'title': 'Media',
+                        'type': 'array',
+                        'items': {
+                            'type': 'string',
+                            'enum': ['copper', 'sfp', 'qsfp28'],
+                        },
+                    },
+                },
+            },
+        )
         devices = (
             create_test_device('Device 1'),
             create_test_device('Device 2'),
         )
 
         module_types = (
-            ModuleType(manufacturer=manufacturer, model='Module Type 1', profile=module_type_profile),
+            ModuleType(
+                manufacturer=manufacturer,
+                model='Module Type 1',
+                profile=module_type_profile,
+                attribute_data={'media': ['copper', 'qsfp28']},
+            ),
             ModuleType(manufacturer=manufacturer, model='Module Type 2'),
             ModuleType(manufacturer=manufacturer, model='Module Type 3'),
             ModuleType(manufacturer=manufacturer, model='Module Type 4'),
@@ -2634,6 +2686,19 @@ class ModuleTestCase(
 
         self.assertContains(response, 'Module Type Profile 1')
 
+    @tag('regression')
+    def test_module_detail_renders_module_type_attribute_lists(self):
+        self.add_permissions(
+            'dcim.view_module',
+            'dcim.view_moduletype',
+            'dcim.view_moduletypeprofile',
+        )
+        response = self.client.get(self._get_queryset().first().get_absolute_url())
+
+        self.assertHttpStatus(response, 200)
+        self.assertContains(response, 'Media')
+        self.assertContains(response, 'copper, qsfp28')
+
     def test_module_component_replication(self):
         self.add_permissions(
             'dcim.view_module',

+ 2 - 1
netbox/extras/api/serializers_/attachments.py

@@ -19,12 +19,13 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
     parent = GFKSerializerField(read_only=True)
     image_width = serializers.IntegerField(read_only=True)
     image_height = serializers.IntegerField(read_only=True)
+    image_size = serializers.IntegerField(read_only=True)
 
     class Meta:
         model = ImageAttachment
         fields = [
             'id', 'url', 'display', 'object_type', 'object_id', 'parent', 'name', 'image', 'description',
-            'image_height', 'image_width', 'created', 'last_updated',
+            'image_height', 'image_width', 'image_size', 'created', 'last_updated',
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'image', 'description')
 

+ 12 - 1
netbox/extras/api/serializers_/scripts.py

@@ -37,6 +37,13 @@ class ScriptModuleSerializer(ValidatedModelSerializer):
         # Pop 'file' before model instantiation — ScriptModule has no such field.
         file = data.pop('file', None)
         data['file_root'] = ManagedFileRootPathChoices.SCRIPTS
+
+        # Reject duplicates before writing to storage so a failed upload can't touch the existing file
+        if file is not None and ScriptModule.objects.filter(
+            file_root=ManagedFileRootPathChoices.SCRIPTS, file_path=file.name
+        ).exists():
+            raise serializers.ValidationError(_("A script module with this file name already exists."))
+
         data = super().validate(data)
         data.pop('file_root', None)
         if file is not None:
@@ -68,7 +75,11 @@ class ScriptModuleSerializer(ValidatedModelSerializer):
                 )
             raise
         finally:
-            if not created and (file_path := validated_data.get('file_path')):
+            # Don't delete a path another ScriptModule still references (e.g. a concurrent upload won the race)
+            file_path = validated_data.get('file_path')
+            if not created and file_path and not ScriptModule.objects.filter(
+                file_root=ManagedFileRootPathChoices.SCRIPTS, file_path=file_path
+            ).exists():
                 try:
                     storage.delete(file_path)
                 except Exception:

+ 8 - 0
netbox/extras/constants.py

@@ -6,6 +6,14 @@ from extras.choices import LogLevelChoices
 # Custom fields
 CUSTOMFIELD_EMPTY_VALUES = (None, '', [])
 
+# Maximum number of objects to update per query when provisioning, removing, or renaming custom
+# field data. Bounding the number of rows touched by each statement prevents very large tables from
+# exceeding the database statement timeout (JSONB updates rewrite each affected row). This value
+# sits at the throughput "knee": benchmarking jsonb_set() across a 1M-row table showed throughput
+# plateaus by ~5K rows/statement (raising it further yields no meaningful speedup), while keeping
+# each statement orders of magnitude below a typical statement timeout.
+CUSTOMFIELD_DATA_BATCH_SIZE = 5000
+
 # ImageAttachment
 IMAGE_ATTACHMENT_IMAGE_FORMATS = {
     'avif': 'image/avif',

+ 3 - 1
netbox/extras/filtersets.py

@@ -506,7 +506,9 @@ class ImageAttachmentFilterSet(ChangeLoggedModelFilterSet):
 
     class Meta:
         model = ImageAttachment
-        fields = ('id', 'object_type_id', 'object_id', 'name', 'description', 'image_width', 'image_height')
+        fields = (
+            'id', 'object_type_id', 'object_id', 'name', 'description', 'image_width', 'image_height', 'image_size',
+        )
 
     def search(self, queryset, name, value):
         if not value.strip():

+ 11 - 1
netbox/extras/graphql/filters.py

@@ -24,7 +24,14 @@ if TYPE_CHECKING:
     )
     from extras.graphql.filter_lookups import ExtraChoicesLookup
     from netbox.graphql.enums import ColorEnum
-    from netbox.graphql.filter_lookups import FloatLookup, IntegerLookup, JSONFilter, StringArrayLookup, TreeNodeFilter
+    from netbox.graphql.filter_lookups import (
+        BigIntegerLookup,
+        FloatLookup,
+        IntegerLookup,
+        JSONFilter,
+        StringArrayLookup,
+        TreeNodeFilter,
+    )
     from tenancy.graphql.filters import TenantFilter, TenantGroupFilter
     from users.graphql.filters import GroupFilter, UserFilter
     from virtualization.graphql.filters import ClusterFilter, ClusterGroupFilter, ClusterTypeFilter
@@ -275,6 +282,9 @@ class ImageAttachmentFilter(ChangeLoggedModelFilter):
     image_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
         strawberry_django.filter_field()
     )
+    image_size: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
+        strawberry_django.filter_field()
+    )
     name: StrFilterLookup | None = strawberry_django.filter_field()
 
 

+ 62 - 0
netbox/extras/management/commands/populate_image_sizes.py

@@ -0,0 +1,62 @@
+from django.core.management.base import BaseCommand
+
+from extras.models import ImageAttachment
+
+# Number of records to read and write per batch
+BATCH_SIZE = 100
+
+
+class Command(BaseCommand):
+    help = "Populate the image_size field for ImageAttachments that predate it"
+
+    def handle(self, *args, **options):
+        verbosity = options['verbosity']
+
+        # Only consider attachments whose size has not yet been cached. This is safe to re-run: rows whose file
+        # was unreadable on a previous run remain NULL and will be retried.
+        queryset = ImageAttachment.objects.filter(image_size__isnull=True)
+        total = queryset.count()
+
+        if not total:
+            if verbosity:
+                self.stdout.write(self.style.SUCCESS("No image attachments require updating."))
+            return
+
+        if verbosity:
+            self.stdout.write(f"Populating image_size for {total} image attachment(s)...")
+
+        updated = 0
+        skipped = 0
+        batch = []
+
+        for processed, attachment in enumerate(queryset.iterator(chunk_size=BATCH_SIZE), start=1):
+            # These rows have image_size=NULL, so the size property reads the file from storage (returning None if
+            # it's inaccessible) rather than returning a cached value.
+            size = attachment.size
+            if size is None:
+                # File is inaccessible; leave image_size NULL so a future run can retry.
+                skipped += 1
+            else:
+                attachment.image_size = size
+                batch.append(attachment)
+
+            if len(batch) >= BATCH_SIZE:
+                ImageAttachment.objects.bulk_update(batch, ['image_size'])
+                updated += len(batch)
+                batch = []
+
+            # Reading each file's size may issue a request to the storage backend, so emit periodic progress
+            # for large tables rather than going silent until completion.
+            if verbosity and processed % BATCH_SIZE == 0:
+                self.stdout.write(f"  Processed {processed}/{total}...")
+
+        if batch:
+            ImageAttachment.objects.bulk_update(batch, ['image_size'])
+            updated += len(batch)
+
+        if verbosity:
+            self.stdout.write(self.style.SUCCESS(f"Updated {updated} image attachment(s)."))
+            if skipped:
+                self.stdout.write(self.style.WARNING(
+                    f"Skipped {skipped} inaccessible file(s); re-run this command to retry them."
+                ))

+ 16 - 0
netbox/extras/migrations/0140_imageattachment_image_size.py

@@ -0,0 +1,16 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("extras", "0139_alter_customfieldchoiceset_extra_choices"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="imageattachment",
+            name="image_size",
+            field=models.PositiveBigIntegerField(blank=True, null=True),
+        ),
+    ]

+ 52 - 20
netbox/extras/models/customfields.py

@@ -8,7 +8,7 @@ import jsonschema
 from django import forms
 from django.conf import settings
 from django.core.validators import RegexValidator, ValidationError
-from django.db import models
+from django.db import models, transaction
 from django.db.models import F, Func, Value
 from django.db.models.expressions import RawSQL
 from django.urls import reverse
@@ -19,6 +19,7 @@ from jsonschema.exceptions import ValidationError as JSONValidationError
 
 from core.models import ObjectType
 from extras.choices import *
+from extras.constants import CUSTOMFIELD_DATA_BATCH_SIZE
 from extras.data import CHOICE_SETS
 from extras.fields import ChoiceSetField
 from netbox.context import query_cache
@@ -322,6 +323,32 @@ class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedMo
             return self.choice_set.get_choice_color(value)
         return None
 
+    @staticmethod
+    def _update_object_data(model, **update_kwargs):
+        """
+        Apply an UPDATE to the custom_field_data of every instance of the given model in batches,
+        bounding the number of rows touched by each statement. A single unbounded UPDATE across
+        millions of rows can exceed the database statement timeout, because JSONB updates rewrite
+        each affected row in full. Batches are selected via keyset pagination on the primary key.
+
+        The batched updates are wrapped in a transaction so that the operation remains atomic, as
+        it was when performed by a single UPDATE. This guards against partially-applied data (e.g.
+        a renamed field landing on only some objects) should the loop be interrupted when not
+        already running inside a request's transaction. Batching avoids the statement timeout
+        regardless, as that limit applies per statement rather than per transaction.
+        """
+        with transaction.atomic():
+            last_pk = 0
+            while True:
+                pks = list(
+                    model.objects.filter(pk__gt=last_pk).order_by('pk')
+                    .values_list('pk', flat=True)[:CUSTOMFIELD_DATA_BATCH_SIZE]
+                )
+                if not pks:
+                    break
+                model.objects.filter(pk__in=pks).update(**update_kwargs)
+                last_pk = pks[-1]
+
     def populate_initial_data(self, content_types):
         """
         Populate initial custom field data upon either a) the creation of a new CustomField, or
@@ -333,14 +360,16 @@ class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedMo
         else:
             value = Value(self.default, models.JSONField())
         for ct in content_types:
-            ct.model_class().objects.update(
-                custom_field_data=Func(
-                    F('custom_field_data'),
-                    Value([self.name]),
-                    value,
-                    function='jsonb_set'
+            if model := ct.model_class():
+                self._update_object_data(
+                    model,
+                    custom_field_data=Func(
+                        F('custom_field_data'),
+                        Value([self.name]),
+                        value,
+                        function='jsonb_set'
+                    )
                 )
-            )
 
     def remove_stale_data(self, content_types):
         """
@@ -349,7 +378,8 @@ class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedMo
         """
         for ct in content_types:
             if model := ct.model_class():
-                model.objects.update(
+                self._update_object_data(
+                    model,
                     custom_field_data=F('custom_field_data') - self.name
                 )
 
@@ -359,17 +389,19 @@ class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedMo
         one, copying the value of the old key.
         """
         for ct in self.object_types.all():
-            ct.model_class().objects.update(
-                custom_field_data=Func(
-                    F('custom_field_data') - old_name,
-                    Value([new_name]),
-                    Func(
-                        F('custom_field_data'),
-                        function='jsonb_extract_path_text',
-                        template=f"to_jsonb(%(expressions)s -> '{old_name}')"
-                    ),
-                    function='jsonb_set')
-            )
+            if model := ct.model_class():
+                self._update_object_data(
+                    model,
+                    custom_field_data=Func(
+                        F('custom_field_data') - old_name,
+                        Value([new_name]),
+                        Func(
+                            F('custom_field_data'),
+                            function='jsonb_extract_path_text',
+                            template=f"to_jsonb(%(expressions)s -> '{old_name}')"
+                        ),
+                        function='jsonb_set')
+                )
 
     def clean(self):
         super().clean()

+ 63 - 4
netbox/extras/models/models.py

@@ -702,6 +702,14 @@ class ImageAttachment(ChangeLoggedModel):
     image_width = models.PositiveSmallIntegerField(
         verbose_name=_('image width'),
     )
+    # Unlike image_height/image_width (populated automatically by ImageField), there is no native size_field, so
+    # this is populated in save(). It is nullable because existing rows predate the field and storage reads can
+    # fail; a null value means "not yet computed" and the size property falls back to reading storage.
+    image_size = models.PositiveBigIntegerField(
+        verbose_name=_('image size'),
+        blank=True,
+        null=True,
+    )
     name = models.CharField(
         verbose_name=_('name'),
         max_length=50,
@@ -717,6 +725,27 @@ class ImageAttachment(ChangeLoggedModel):
 
     clone_fields = ('object_type', 'object_id')
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # Cache an identity for the current image so save() can detect a new/replaced file and recompute the cached
+        # image_size. We combine the file name with the (auto-populated) dimensions: a replacement that reuses the
+        # same name is still caught when its dimensions differ. Read the raw image value from __dict__ to avoid
+        # triggering the ImageField descriptor here (doing so during ORM/GraphQL instantiation can recurse).
+        self._orig_image_key = self._image_identity()
+
+    def _image_identity(self):
+        """
+        Return a tuple identifying the current image file for change detection: its name plus the dimensions Django
+        populates from it. All three are read raw from __dict__ to avoid triggering the ImageField descriptor
+        (accessing `self.image` during ORM/GraphQL instantiation can recurse). Not a content fingerprint: a
+        replacement with an identical name AND identical dimensions is not distinguished (would require reading the
+        file, the storage round-trip this caching avoids).
+        """
+        original = self.__dict__.get('image')
+        name = getattr(original, 'name', original)
+        return (name, self.__dict__.get('image_height'), self.__dict__.get('image_width'))
+
     class Meta:
         ordering = ('name', 'pk')  # name may be non-unique
         indexes = (
@@ -772,12 +801,15 @@ class ImageAttachment(ChangeLoggedModel):
             alt_text=escape(self.description or self.name),
         ))
 
-    @property
-    def size(self):
+    def _read_image_size(self):
         """
-        Wrapper around `image.size` to suppress an OSError in case the file is inaccessible. Also opportunistically
-        catch other exceptions that we know other storage back-ends to throw.
+        Read the image file's size from storage, suppressing an OSError in case the file is inaccessible. Also
+        opportunistically catch other exceptions that we know other storage back-ends to throw. Returns None if the
+        size cannot be determined. This may issue a request to the storage backend (e.g. a HEAD request to S3).
         """
+        if not self.image:
+            return None
+
         expected_exceptions = [OSError]
 
         try:
@@ -791,6 +823,33 @@ class ImageAttachment(ChangeLoggedModel):
         except tuple(expected_exceptions):
             return None
 
+    @property
+    def size(self):
+        """
+        Return the size of the image file in bytes. Prefer the cached `image_size` value to avoid a storage request;
+        fall back to reading from storage for legacy rows where `image_size` has not yet been populated.
+        """
+        if self.image_size is not None:
+            return self.image_size
+        return self._read_image_size()
+
+    def save(self, *args, **kwargs):
+        # Populate image_size on creation or when the image file has changed. Reading the size may touch the storage
+        # backend (e.g. a HEAD request to S3), so we only do it when necessary: bulk operations that don't alter the
+        # image (bulk edit, rename) leave the identity unchanged and skip the read entirely. We never overwrite a good
+        # value with None (e.g. on a transient storage error); a failed read while replacing a file keeps the prior
+        # size until the next successful save, which is preferred over storing None.
+        orig_image_key = getattr(self, '_orig_image_key', None)
+        if self._state.adding or self._image_identity() != orig_image_key:
+            size = self._read_image_size()
+            if size is not None:
+                self.image_size = size
+
+        super().save(*args, **kwargs)
+
+        # Refresh the cached identity so subsequent saves on this instance detect further changes correctly.
+        self._orig_image_key = self._image_identity()
+
     def to_objectchange(self, action):
         objectchange = super().to_objectchange(action)
         objectchange.related_object = self.parent

+ 1 - 1
netbox/extras/tables/tables.py

@@ -424,7 +424,7 @@ class NotificationTable(NetBoxTable):
         orderable=False,
         attrs={
             'td': {'class': 'w-1'},
-            'th': {'class': 'w-1'},
+            'th': {'class': 'w-1', 'aria-label': _('Type')},
         },
         verbose_name=''
     )

+ 2 - 1
netbox/extras/templatetags/custom_links.py

@@ -33,8 +33,9 @@ def custom_links(context, obj):
     """
     Render all applicable links for the given object.
     """
+    user = context['request'].user
     object_type = ObjectType.objects.get_for_model(obj)
-    custom_links = CustomLink.objects.filter(object_types=object_type, enabled=True)
+    custom_links = CustomLink.objects.restrict(user, 'view').filter(object_types=object_type, enabled=True)
     if not custom_links:
         return ''
 

+ 73 - 3
netbox/extras/tests/test_api.py

@@ -775,7 +775,8 @@ class ImageAttachmentTestCase(
                 name='Image Attachment 1',
                 image='http://example.com/image1.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=1024
             ),
             ImageAttachment(
                 object_type=ct,
@@ -783,7 +784,8 @@ class ImageAttachmentTestCase(
                 name='Image Attachment 2',
                 image='http://example.com/image2.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=2048
             ),
             ImageAttachment(
                 object_type=ct,
@@ -791,7 +793,8 @@ class ImageAttachmentTestCase(
                 name='Image Attachment 3',
                 image='http://example.com/image3.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=4096
             )
         )
         ImageAttachment.objects.bulk_create(image_attachments)
@@ -1620,6 +1623,27 @@ class NotificationTestCase(APIViewTestCases.APIViewTestCase):
         ]
 
 
+class _InMemoryScriptStorage:
+    """Stateful stand-in for the scripts storage backend; mimics allow_overwrite=True."""
+
+    def __init__(self):
+        self.files = {}
+
+    def save(self, name, content):
+        content.seek(0)
+        self.files[name] = content.read()
+        return name
+
+    def open(self, name, mode='rb'):
+        return io.BytesIO(self.files[name])
+
+    def delete(self, name):
+        self.files.pop(name, None)
+
+    def exists(self, name):
+        return name in self.files
+
+
 class ScriptModuleTestCase(APITestCase):
     """
     Tests for the POST /api/extras/scripts/upload/ endpoint.
@@ -1692,6 +1716,52 @@ class ScriptModuleTestCase(APITestCase):
         self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
         self.assertFalse(ScriptModule.objects.filter(file_path='test_faulty.py').exists())
 
+    def test_upload_duplicate_script_module_preserves_existing_file(self):
+        """A duplicate-filename upload returns 400 and leaves the existing file unchanged."""
+        self.add_permissions('extras.add_scriptmodule', 'core.add_managedfile')
+        original_content = (
+            b"from extras.scripts import Script\n\n\n"
+            b"class ProbeScript(Script):\n    def run(self, data, commit):\n        return 'v1'\n"
+        )
+        updated_content = original_content.replace(b"'v1'", b"'v2'")
+
+        fake_storage = _InMemoryScriptStorage()
+
+        with (
+            patch('extras.api.serializers_.scripts.storages') as mock_serializer_storages,
+            patch('extras.models.mixins.storages') as mock_module_storages,
+        ):
+            mock_serializer_storages.create_storage.return_value = fake_storage
+            mock_serializer_storages.backends = {'scripts': {}}
+            mock_module_storages.__getitem__.return_value = fake_storage
+
+            # First upload succeeds and writes the file
+            response = self.client.post(
+                self.url,
+                {'file': SimpleUploadedFile('zz_probe.py', original_content, content_type='text/plain')},
+                format='multipart',
+                **self.header,
+            )
+            self.assertHttpStatus(response, status.HTTP_201_CREATED)
+            self.assertEqual(fake_storage.files['zz_probe.py'], original_content)
+
+            # Re-uploading the same filename with different content must be rejected
+            response = self.client.post(
+                self.url,
+                {'file': SimpleUploadedFile('zz_probe.py', updated_content, content_type='text/plain')},
+                format='multipart',
+                **self.header,
+            )
+            self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+            self.assertIn('already exists', str(response.data))
+
+            # Existing file must survive intact: neither deleted nor overwritten with v2
+            self.assertTrue(fake_storage.exists('zz_probe.py'))
+            self.assertEqual(fake_storage.files['zz_probe.py'], original_content)
+
+        # Exactly one ScriptModule remains, still pointing at the original file
+        self.assertEqual(ScriptModule.objects.filter(file_path='zz_probe.py').count(), 1)
+
     def test_upload_script_module_without_file_fails(self):
         self.add_permissions('extras.add_scriptmodule', 'core.add_managedfile')
         response = self.client.post(self.url, {}, format='json', **self.header)

+ 42 - 0
netbox/extras/tests/test_customfields.py

@@ -1,6 +1,7 @@
 import datetime
 import json
 from decimal import Decimal
+from unittest.mock import patch
 
 from django.core.exceptions import ValidationError
 from django.test import tag
@@ -628,6 +629,47 @@ class CustomFieldTestCase(TestCase):
         self.assertNotIn('field1', site.custom_field_data)
         self.assertEqual(site.custom_field_data['field2'], FIELD_DATA)
 
+    @patch('extras.models.customfields.CUSTOMFIELD_DATA_BATCH_SIZE', 2)
+    def test_batched_object_data_updates(self):
+        """
+        Provisioning, renaming, and removing custom field data is applied in batches. Use a small
+        batch size to ensure the data on every object is updated across multiple batches.
+        """
+        # The existing sites (created in setUpTestData) span multiple batches of size 2
+        site_count = Site.objects.count()
+        self.assertGreater(site_count, 2)
+
+        # Provisioning: a default value is populated onto every existing object
+        cf = CustomField.objects.create(
+            name='batched_field',
+            type=CustomFieldTypeChoices.TYPE_TEXT,
+            default='foo'
+        )
+        cf.object_types.set([self.object_type])
+        self.assertEqual(
+            Site.objects.filter(custom_field_data__batched_field='foo').count(),
+            site_count
+        )
+
+        # Renaming: the key is renamed on every existing object, preserving its value
+        cf.name = 'renamed_field'
+        cf.save()
+        self.assertEqual(
+            Site.objects.filter(custom_field_data__renamed_field='foo').count(),
+            site_count
+        )
+        self.assertEqual(
+            Site.objects.filter(custom_field_data__has_key='batched_field').count(),
+            0
+        )
+
+        # Removal: the key is stripped from every existing object when the field is deleted
+        cf.delete()
+        self.assertEqual(
+            Site.objects.filter(custom_field_data__has_key='renamed_field').count(),
+            0
+        )
+
     def test_default_value_validation(self):
         choiceset = CustomFieldChoiceSet.objects.create(
             name="Test Choice Set",

+ 19 - 4
netbox/extras/tests/test_filtersets.py

@@ -741,7 +741,8 @@ class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
                 name='Image Attachment 1',
                 image='http://example.com/image1.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=1024
             ),
             ImageAttachment(
                 object_type=site_ct,
@@ -749,7 +750,8 @@ class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
                 name='Image Attachment 2',
                 image='http://example.com/image2.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=2048
             ),
             ImageAttachment(
                 object_type=rack_ct,
@@ -757,7 +759,8 @@ class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
                 name='Image Attachment 3',
                 image='http://example.com/image3.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=4096
             ),
             ImageAttachment(
                 object_type=rack_ct,
@@ -765,7 +768,8 @@ class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
                 name='Image Attachment 4',
                 image='http://example.com/image4.png',
                 image_height=100,
-                image_width=100
+                image_width=100,
+                image_size=8192
             )
         )
         ImageAttachment.objects.bulk_create(image_attachments)
@@ -789,6 +793,17 @@ class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
         }
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
 
+    def test_image_size(self):
+        # Fixtures set image_size to 1024, 2048, 4096, 8192.
+        params = {'image_size': [1024, 2048]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+    def test_image_size_range(self):
+        # __gte/__lte bound the 1024/2048/4096/8192 fixtures to the middle two. NetBox's auto-generated numeric
+        # lookups are multi-value, so values are passed as lists.
+        params = {'image_size__gte': [2048], 'image_size__lte': [4096]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
 
 class TableConfigTestCase(TestCase, ChangeLoggedFilterSetTests):
     queryset = TableConfig.objects.all()

+ 64 - 1
netbox/extras/tests/test_management_commands.py

@@ -12,7 +12,8 @@ from dcim.choices import InterfaceTypeChoices
 from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site
 from extras.management.commands import renaturalize, webhook_receiver
 from extras.management.commands.webhook_receiver import WebhookHandler
-from extras.models import ConfigContext
+from extras.models import ConfigContext, ImageAttachment
+from extras.tests.test_models import OverwriteStyleMemoryStorage, UnreadableSizeMemoryStorage
 from users.models import User
 from utilities.fields import NaturalOrderingField
 from virtualization.models import VirtualMachine
@@ -586,3 +587,65 @@ class WebhookReceiverTestCase(TestCase):
 
         print_.assert_any_call('(No body)')
         print_.assert_any_call('Completed request #1')
+
+
+class PopulateImageSizesTestCase(TestCase):
+    @classmethod
+    def setUpTestData(cls):
+        cls.ct_site = ContentType.objects.get_by_natural_key('dcim', 'site')
+        cls.site = Site.objects.create(name='Site 1', slug='site-1')
+
+    def _legacy_attachment(self, name, image_name):
+        # bulk_create skips save(), so image_size starts NULL, mimicking a row created before the field existed.
+        attachment = ImageAttachment(
+            object_type=self.ct_site,
+            object_id=self.site.pk,
+            name=name,
+            image=image_name,
+            image_height=100,
+            image_width=100,
+        )
+        ImageAttachment.objects.bulk_create([attachment])
+        return ImageAttachment.objects.get(name=name)
+
+    def test_populates_null_image_sizes(self):
+        field = ImageAttachment._meta.get_field('image')
+        storage = OverwriteStyleMemoryStorage()
+        storage.files['image-attachments/site_1_a.png'] = b'\x00' * 321
+
+        attachment = self._legacy_attachment('Legacy 1', 'image-attachments/site_1_a.png')
+        self.assertIsNone(attachment.image_size)
+
+        out = StringIO()
+        with patch.object(field, 'storage', storage):
+            call_command('populate_image_sizes', stdout=out)
+            # Read the persisted value back under the patched storage (refreshing the image field re-reads
+            # dimensions from storage, which must be the in-memory backend).
+            persisted = ImageAttachment.objects.get(pk=attachment.pk)
+            self.assertEqual(persisted.image_size, 321)
+
+        self.assertIn('Updated 1', out.getvalue())
+
+    def test_skips_unreadable_files_and_is_rerunnable(self):
+        field = ImageAttachment._meta.get_field('image')
+        attachment = self._legacy_attachment('Legacy 2', 'image-attachments/site_1_missing.png')
+
+        # First run: storage can't report size, so the row is skipped and left NULL.
+        out = StringIO()
+        with patch.object(field, 'storage', UnreadableSizeMemoryStorage()):
+            call_command('populate_image_sizes', stdout=out)
+            self.assertIsNone(ImageAttachment.objects.get(pk=attachment.pk).image_size)
+        self.assertIn('Skipped 1', out.getvalue())
+
+        # Second run: storage now works, and the previously-skipped row is picked up.
+        storage = OverwriteStyleMemoryStorage()
+        storage.files['image-attachments/site_1_missing.png'] = b'\x00' * 654
+        out = StringIO()
+        with patch.object(field, 'storage', storage):
+            call_command('populate_image_sizes', stdout=out)
+            self.assertEqual(ImageAttachment.objects.get(pk=attachment.pk).image_size, 654)
+
+    def test_noop_when_nothing_to_update(self):
+        out = StringIO()
+        call_command('populate_image_sizes', stdout=out)
+        self.assertIn('No image attachments require updating.', out.getvalue())

+ 208 - 0
netbox/extras/tests/test_models.py

@@ -74,6 +74,16 @@ class OverwriteStyleMemoryStorage(Storage):
         return f'https://example.invalid/{name}'
 
 
+class UnreadableSizeMemoryStorage(OverwriteStyleMemoryStorage):
+    """
+    Like OverwriteStyleMemoryStorage, but size() raises OSError to model a storage backend that is
+    transiently unavailable (e.g. an S3 outage) when reading file size.
+    """
+
+    def size(self, name):
+        raise OSError('storage unavailable')
+
+
 class ImageAttachmentTestCase(TestCase):
     @classmethod
     def setUpTestData(cls):
@@ -191,6 +201,204 @@ class ImageAttachmentTestCase(TestCase):
 
         self.assertCountEqual(storage.files.keys(), {base_name, suffixed_name})
 
+    def test_save_populates_image_size_on_create(self):
+        """
+        save() populates image_size from the uploaded file on creation.
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('size-on-create.png'),
+            )
+            ia.save()
+
+            self.assertIsNotNone(ia.image_size)
+            self.assertEqual(ia.image_size, ia.image.size)
+
+    def test_size_property_returns_stored_value_without_storage_access(self):
+        """
+        The size property returns the cached image_size rather than the file's actual size. The stub's empty
+        file reports size 0, so asserting the distinct stored value proves the property used the cached value.
+        """
+        ia = self._stub_image_attachment(self.site.pk, 'image-attachments/site_1_no-file.png')
+        self.assertEqual(ia._read_image_size(), 0)  # the stub's empty file genuinely reports 0
+        ia.image_size = 9999
+
+        self.assertEqual(ia.size, 9999)
+
+    def test_size_property_falls_back_to_storage_when_unset(self):
+        """
+        For legacy rows where image_size is NULL, the size property falls back to reading storage
+        (rather than reporting 0 bytes).
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('fallback.png'),
+            )
+            ia.save()
+
+            # Simulate a legacy row that predates the image_size field.
+            ia.image_size = None
+            self.assertEqual(ia.size, ia.image.size)
+            self.assertGreater(ia.size, 0)
+
+    def test_save_does_not_clobber_existing_size_on_storage_error(self):
+        """
+        When the storage backend raises on a size read (modeled by a real Storage subclass, not a mock),
+        save() must not overwrite an existing image_size with None.
+        """
+        field = ImageAttachment._meta.get_field('image')
+
+        # Create a row with a real, readable size.
+        with patch.object(field, 'storage', OverwriteStyleMemoryStorage()):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('keep-size.png'),
+            )
+            ia.save()
+            original_size = ia.image_size
+            self.assertIsNotNone(original_size)
+
+        # Reload from the DB so the FieldFile has no cached size and must consult storage (as it would for a
+        # row loaded fresh in production). With the backend unable to report size, the read fails (returns None),
+        # and save() must keep the previously-stored value rather than clobbering it with None.
+        with patch.object(field, 'storage', UnreadableSizeMemoryStorage()):
+            reloaded = ImageAttachment.objects.get(pk=ia.pk)
+            self.assertIsNone(reloaded._read_image_size())  # the read genuinely fails (returns None)
+            # Make the image look replaced by perturbing the cached identity (different name component).
+            reloaded._orig_image_key = ('image-attachments/site_1_old.png', reloaded.image_height, reloaded.image_width)
+            reloaded.save()
+
+            # In-memory value is preserved, and the persisted value is unchanged.
+            self.assertEqual(reloaded.image_size, original_size)
+            self.assertEqual(ImageAttachment.objects.get(pk=ia.pk).image_size, original_size)
+
+    def test_save_recomputes_image_size_when_image_replaced(self):
+        """
+        Replacing the image on an existing row recomputes image_size (Cable-style change detection).
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('original.png'),
+            )
+            ia.save()
+            original_size = ia.image_size
+            self.assertIsNotNone(original_size)
+
+            # Replace the image with a larger file and save again.
+            larger = SimpleUploadedFile(
+                name='replacement.png',
+                content=self._uploaded_png('replacement.png').read() + b'\x00' * 100,
+                content_type='image/png',
+            )
+            ia.image = larger
+            ia.save()
+
+            self.assertEqual(ia.image_size, ia.image.size)
+            self.assertNotEqual(ia.image_size, original_size)
+
+    def test_image_identity_includes_dimensions(self):
+        """
+        The change-detection key combines the image name with its dimensions, so a replacement that reuses the
+        same name but changes dimensions produces a different key (which name alone would not).
+        """
+        ia = self._stub_image_attachment(self.site.pk, 'image-attachments/site_1_same.png')
+        ia.image_height, ia.image_width = 10, 10
+        key_small = ia._image_identity()
+
+        # Same name, different dimensions (as Django would set when a same-named file is replaced).
+        ia.image_height, ia.image_width = 40, 40
+        key_large = ia._image_identity()
+
+        self.assertEqual(key_small[0], key_large[0])   # name component unchanged
+        self.assertNotEqual(key_small, key_large)      # but the key differs, so save() will recompute
+
+    def test_save_recomputes_image_size_when_dimensions_change_under_same_name(self):
+        """
+        When the image is replaced by a file with the same stored name but different dimensions, save()
+        recomputes image_size. Name-only detection would miss this; the dimension component catches it.
+        Simulates the same-name case by priming the cached identity with the old dimensions.
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('same-name.png'),
+            )
+            ia.save()
+            name = ia.image.name
+
+            # Force the cached identity to reflect the SAME name but different (old) dimensions, then bump the
+            # current dimensions to mimic a same-name replacement with a differently-sized image.
+            ia._orig_image_key = (name, ia.image_height + 5, ia.image_width + 5)
+            ia.save()
+
+            self.assertEqual(ia.image.name, name)                 # name unchanged
+            self.assertEqual(ia.image_size, ia.image.size)        # size recomputed despite same name
+
+    def test_save_without_touching_image_does_not_recompute_or_read_storage(self):
+        """
+        Editing an existing row without replacing the image leaves image_size untouched and does not
+        hit storage. Directly guards against the change-detection comparison misfiring.
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                name='Original',
+                image=self._uploaded_png('untouched.png'),
+            )
+            ia.save()
+            stored_size = ia.image_size
+
+            # Reload from the DB so the cached image identity is set from the persisted value, then edit only the name.
+            reloaded = ImageAttachment.objects.get(pk=ia.pk)
+            reloaded.name = 'Renamed'
+            with patch.object(ImageAttachment, '_read_image_size', side_effect=AssertionError('storage accessed')):
+                reloaded.save()
+
+            self.assertEqual(reloaded.image_size, stored_size)
+
+    def test_save_populates_image_size_via_constructor_kwarg(self):
+        """
+        The non-UI create path (constructor kwarg / REST / bulk) populates image_size correctly,
+        confirming change detection behaves when image is passed as a FieldFile.
+        """
+        storage = OverwriteStyleMemoryStorage()
+        field = ImageAttachment._meta.get_field('image')
+
+        with patch.object(field, 'storage', storage):
+            ia = ImageAttachment(
+                object_type=self.ct_site,
+                object_id=self.site.pk,
+                image=self._uploaded_png('kwarg.png'),
+            )
+            ia.save()
+
+            self.assertIsNotNone(ia.image_size)
+            self.assertEqual(ia.image_size, ia.image.size)
+
 
 class TableConfigTestCase(TestCase):
     @classmethod

+ 75 - 0
netbox/extras/tests/test_templatetags.py

@@ -0,0 +1,75 @@
+from django.contrib.auth import get_user_model
+from django.contrib.auth.context_processors import PermWrapper
+from django.test import RequestFactory, TestCase
+
+from core.models import ObjectType
+from dcim.models import Site
+from extras.models import CustomLink
+from extras.templatetags.custom_links import custom_links
+from users.models import ObjectPermission
+
+User = get_user_model()
+
+
+class CustomLinkTemplateTagTest(TestCase):
+    """
+    The custom_links template tag must honor object-level permissions on CustomLink (see #22439).
+    """
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.site = Site.objects.create(name='Site 1', slug='site-1')
+        cls.custom_link = CustomLink.objects.create(
+            name='Custom Link 1',
+            enabled=True,
+            weight=100,
+            new_window=False,
+            link_text='Link 1',
+            link_url='http://example.com/'
+        )
+        cls.custom_link.object_types.set([ObjectType.objects.get_for_model(Site)])
+
+    def render(self, user):
+        request = RequestFactory().get('/')
+        request.user = user
+        context = {
+            'request': request,
+            'user': user,
+            'perms': PermWrapper(user),
+        }
+        return custom_links(context, self.site)
+
+    def test_no_permission_hides_link(self):
+        # A user without the view_customlink permission must not see the link.
+        user = User.objects.create_user(username='user1')
+        self.assertNotIn('Link 1', self.render(user))
+
+    def test_constrained_permission_hides_link(self):
+        # A user granted view_customlink via a constraint that excludes the link must not see it (#22439).
+        user = User.objects.create_user(username='user2')
+        permission = ObjectPermission.objects.create(
+            name='Constrained custom links',
+            actions=['view'],
+            constraints={'name': 'Some Other Link'}  # Does not match Custom Link 1
+        )
+        permission.object_types.set([ObjectType.objects.get_for_model(CustomLink)])
+        permission.users.set([user])
+
+        # Re-fetch to clear any cached permissions
+        user = User.objects.get(pk=user.pk)
+        self.assertNotIn('Link 1', self.render(user))
+
+    def test_permitted_link_is_shown(self):
+        # A user granted view_customlink covering the link must see it.
+        user = User.objects.create_user(username='user3')
+        permission = ObjectPermission.objects.create(
+            name='Custom links',
+            actions=['view'],
+            constraints={'name': 'Custom Link 1'}  # Matches Custom Link 1
+        )
+        permission.object_types.set([ObjectType.objects.get_for_model(CustomLink)])
+        permission.users.set([user])
+
+        # Re-fetch to clear any cached permissions
+        user = User.objects.get(pk=user.pk)
+        self.assertIn('Link 1', self.render(user))

+ 45 - 1
netbox/extras/tests/test_views.py

@@ -184,7 +184,7 @@ class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
 
 
 class CustomLinkRenderingTestCase(TestCase):
-    user_permissions = ['dcim.view_site']
+    user_permissions = ['dcim.view_site', 'extras.view_customlink']
 
     def test_view_object_with_custom_link(self):
         customlink = CustomLink(
@@ -203,6 +203,47 @@ class CustomLinkRenderingTestCase(TestCase):
         self.assertEqual(response.status_code, 200)
         self.assertIn(f'FOO {site.name} BAR', str(response.content))
 
+    def test_list_view_custom_link_column(self):
+        # A custom link column must render in the list view when the user can view the CustomLink.
+        customlink = CustomLink(
+            name='Test',
+            link_text='FOO {{ object.name }} BAR',
+            link_url='http://example.com/?site={{ object.slug }}',
+            new_window=False
+        )
+        customlink.save()
+        customlink.object_types.set([ObjectType.objects.get_for_model(Site)])
+
+        site = Site(name='Test Site', slug='test-site')
+        site.save()
+
+        # Custom link columns are hidden by default; explicitly include the column
+        response = self.client.get(f"{reverse('dcim:site_list')}?include_columns=cl_Test")
+        self.assertEqual(response.status_code, 200)
+        self.assertIn(f'FOO {site.name} BAR', str(response.content))
+
+    def test_list_view_custom_link_column_hidden_without_permission(self):
+        # A custom link column must be excluded from the list view when the user cannot view the
+        # CustomLink, even if explicitly requested (#22439).
+        customlink = CustomLink(
+            name='Test',
+            link_text='FOO {{ object.name }} BAR',
+            link_url='http://example.com/?site={{ object.slug }}',
+            new_window=False
+        )
+        customlink.save()
+        customlink.object_types.set([ObjectType.objects.get_for_model(Site)])
+
+        site = Site(name='Test Site', slug='test-site')
+        site.save()
+
+        # Revoke permission to view custom links
+        self.remove_permissions('extras.view_customlink')
+
+        response = self.client.get(f"{reverse('dcim:site_list')}?include_columns=cl_Test")
+        self.assertEqual(response.status_code, 200)
+        self.assertNotIn(f'FOO {site.name} BAR', str(response.content))
+
 
 class SavedFilterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
     model = SavedFilter
@@ -440,6 +481,7 @@ class ImageAttachmentTestCase(
                     image='http://example.com/image1.png',
                     image_height=100,
                     image_width=100,
+                    image_size=1024,
                 ),
                 ImageAttachment(
                     object_type=ct,
@@ -448,6 +490,7 @@ class ImageAttachmentTestCase(
                     image='http://example.com/image2.png',
                     image_height=100,
                     image_width=100,
+                    image_size=2048,
                 ),
                 ImageAttachment(
                     object_type=ct,
@@ -456,6 +499,7 @@ class ImageAttachmentTestCase(
                     image='http://example.com/image3.png',
                     image_height=100,
                     image_width=100,
+                    image_size=4096,
                 ),
             ]
         )

+ 4 - 4
netbox/ipam/forms/bulk_import.py

@@ -429,8 +429,8 @@ class IPAddressImportForm(PrimaryModelImportForm):
         ipaddress = super().save(*args, **kwargs)
 
         # Set as primary for device/VM
-        if self.cleaned_data.get('is_primary') is not None:
-            parent = self.cleaned_data.get('device') or self.cleaned_data.get('virtual_machine')
+        parent = self.cleaned_data.get('device') or self.cleaned_data.get('virtual_machine')
+        if parent and self.cleaned_data.get('is_primary') is not None:
             if self.cleaned_data.get('is_primary'):
                 parent.snapshot()
                 if self.instance.address.version == 4:
@@ -450,8 +450,8 @@ class IPAddressImportForm(PrimaryModelImportForm):
                     parent.save()
 
         # Set as OOB for device
-        if self.cleaned_data.get('is_oob') is not None:
-            parent = self.cleaned_data.get('device')
+        parent = self.cleaned_data.get('device')
+        if parent and self.cleaned_data.get('is_oob') is not None:
             if self.cleaned_data.get('is_oob'):
                 parent.snapshot()
                 parent.oob_ip = ipaddress

+ 71 - 0
netbox/ipam/tests/test_forms.py

@@ -67,6 +67,77 @@ class IPAddressImportFormTestCase(TestCase):
             type=InterfaceTypeChoices.TYPE_1GE_FIXED,
         )
 
+    def test_import_with_empty_is_primary_column_no_device(self):
+        """
+        Regression test for #22561: importing an IP where the is_primary/is_oob columns are
+        present but empty (and no device/VM specified) should succeed, not raise AttributeError.
+        """
+        form = IPAddressImportForm(data={
+            'address': '172.16.0.1/20',
+            'status': 'active',
+            'device': '',
+            'virtual_machine': '',
+            'interface': '',
+            'is_primary': '',
+            'is_oob': '',
+            'description': 'gateway for group A - Site 01',
+        })
+        self.assertTrue(form.is_valid(), form.errors)
+        ip = form.save()
+        self.assertEqual(str(ip.address), '172.16.0.1/20')
+
+    def test_import_with_false_is_primary_no_device(self):
+        """
+        Regression test for #22561: importing an IP with an explicit is_primary=false (and no
+        device/VM specified) should succeed as a no-op, not raise AttributeError. An explicit
+        falsy boolean is not caught by clean_is_primary()'s "column absent" check.
+        """
+        form = IPAddressImportForm(data={
+            'address': '172.16.0.1/20',
+            'status': 'active',
+            'is_primary': 'false',
+            'is_oob': 'false',
+            'description': 'no parent specified',
+        })
+        self.assertTrue(form.is_valid(), form.errors)
+        ip = form.save()
+        self.assertEqual(str(ip.address), '172.16.0.1/20')
+
+    def test_primary_not_cleared_by_subsequent_non_primary_row_with_device(self):
+        """
+        Guard against re-breaking #21440 while fixing #22561: importing a second IP with
+        is_primary=false (device specified) must not clear the primary IP set by a previous
+        row. The save-side parent guard must leave the conservative "only clear if currently
+        primary" behavior intact.
+        """
+        form1 = IPAddressImportForm(data={
+            'address': '10.10.10.1/24',
+            'status': 'active',
+            'device': 'Device 1',
+            'interface': 'eth0',
+            'is_primary': True,
+        })
+        self.assertTrue(form1.is_valid(), form1.errors)
+        ip1 = form1.save()
+
+        self.device.refresh_from_db()
+        self.assertEqual(self.device.primary_ip4, ip1)
+
+        form2 = IPAddressImportForm(data={
+            'address': '10.10.10.2/24',
+            'status': 'active',
+            'device': 'Device 1',
+            'interface': 'eth0',
+            'is_primary': False,
+        })
+        self.assertTrue(form2.is_valid(), form2.errors)
+        form2.save()
+
+        self.device.refresh_from_db()
+        self.assertEqual(
+            self.device.primary_ip4, ip1, "primary IP was incorrectly cleared by a row with is_primary=False"
+        )
+
     def test_oob_import_not_cleared_by_subsequent_non_oob_row(self):
         """
         Regression test for #21440: importing a second IP with is_oob=False should

+ 9 - 2
netbox/netbox/api/gfk_fields.py

@@ -10,10 +10,17 @@ __all__ = (
 
 @extend_schema_field(serializers.JSONField(allow_null=True, read_only=True))
 class GFKSerializerField(serializers.Field):
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        self._serializer_cache = {}
 
     def to_representation(self, instance, **kwargs):
         if instance is None:
             return None
-        serializer = get_serializer_for_model(instance)
         context = {'request': self.context['request']}
-        return serializer(instance, nested=True, context=context).data
+        if instance.__class__ not in self._serializer_cache:
+            serializer = get_serializer_for_model(instance)(nested=True, context=context)
+            self._serializer_cache[instance.__class__] = serializer
+        else:
+            serializer = self._serializer_cache[instance.__class__]
+        return serializer.to_representation(instance)

+ 3 - 1
netbox/netbox/authentication/misc.py

@@ -31,7 +31,9 @@ def _mirror_groups(self):
     Mirrors the user's LDAP groups in the Django database and updates the
     user's membership.
     """
-    target_group_names = frozenset(self._get_groups().get_group_names())
+    target_group_names = frozenset(
+        filter(None, self._get_groups().get_group_names())
+    )
     current_group_names = frozenset(
         self._user.groups.values_list("name", flat=True).iterator()
     )

+ 3 - 3
netbox/netbox/middleware.py

@@ -105,8 +105,8 @@ class CoreMiddleware:
         if settings.DEBUG:
             return None
 
-        # Cleanly handle exceptions that occur from REST API requests
-        if is_api_request(request):
+        # Cleanly handle exceptions that occur from REST or GraphQL API requests
+        if is_api_request(request) or is_graphql_request(request):
             # Fire Django's got_request_exception signal so error-tracking
             # integrations (e.g. Sentry) capture the exception.
             got_request_exception.send(sender=self.__class__, request=request)
@@ -283,7 +283,7 @@ class MaintenanceModeMiddleware:
             error_message = 'NetBox is currently operating in maintenance mode and is unable to perform write ' \
                             'operations. Please try again later.'
 
-            if is_api_request(request):
+            if is_api_request(request) or is_graphql_request(request):
                 return handle_rest_api_exception(request, error=error_message)
 
             messages.error(request, error_message)

+ 4 - 4
netbox/netbox/settings.py

@@ -255,13 +255,13 @@ if not LOGIN_REQUIRED:
     warnings.warn(
         "LOGIN_REQUIRED is deprecated and will be removed in NetBox v5.0. Unauthenticated access to the application "
         "will no longer be supported. Please plan to require authentication for all users before upgrading.",
-        DeprecationWarning,
+        FutureWarning,
     )
 elif hasattr(configuration, 'LOGIN_REQUIRED'):
     warnings.warn(
         "LOGIN_REQUIRED is deprecated and will be removed in NetBox v5.0. This parameter can be removed from your "
         "configuration file.",
-        DeprecationWarning,
+        FutureWarning,
     )
 if hasattr(configuration, 'JINJA2_FILTERS'):
     warnings.warn(
@@ -298,13 +298,13 @@ if STORAGE_BACKEND is not None:
     else:
         warnings.warn(
             "STORAGE_BACKEND is deprecated, use the new STORAGES setting instead.",
-            DeprecationWarning,
+            FutureWarning,
         )
 
 if STORAGE_CONFIG is not None:
     warnings.warn(
         "STORAGE_CONFIG is deprecated, use the new STORAGES setting instead.",
-        DeprecationWarning,
+        FutureWarning,
     )
 
 # Default STORAGES for Django

+ 3 - 0
netbox/netbox/tables/columns.py

@@ -249,6 +249,9 @@ class ActionsColumn(tables.Column):
         direct button link and icon (default: True)
     """
     attrs = {
+        'th': {
+            'aria-label': _('Actions'),
+        },
         'td': {
             'class': 'text-end text-nowrap noprint p-1'
         }

+ 32 - 0
netbox/netbox/tables/tables.py

@@ -287,6 +287,38 @@ class NetBoxTable(BaseTable):
 
         super().__init__(*args, extra_columns=extra_columns, **kwargs)
 
+    def configure(self, request):
+        # Remove custom link columns referencing CustomLinks the user cannot view (#22439).
+        # These columns are added for all enabled CustomLinks in __init__(), before the request
+        # (and thus the user) is known, so object-level permissions are enforced here instead.
+        self._restrict_customlink_columns(request.user)
+
+        super().configure(request)
+
+    def _restrict_customlink_columns(self, user):
+        """
+        Exclude any custom link columns which reference a CustomLink the user does not have
+        permission to view.
+        """
+        customlinks = {
+            name: column.column.customlink
+            for name, column in self.columns.iteritems()
+            if isinstance(column.column, columns.CustomLinkColumn)
+        }
+        if not customlinks:
+            return
+
+        permitted = set(
+            CustomLink.objects.restrict(user, 'view').filter(
+                pk__in=[cl.pk for cl in customlinks.values()]
+            ).values_list('pk', flat=True)
+        )
+        excluded = tuple(
+            name for name, customlink in customlinks.items() if customlink.pk not in permitted
+        )
+        if excluded:
+            self.exclude = (*self.exclude, *excluded)
+
     @cached_property
     def htmx_url(self):
         """

+ 0 - 0
netbox/netbox/tests/dummy_plugin/tests/__init__.py


+ 19 - 0
netbox/netbox/tests/dummy_plugin/tests/test_graphql.py

@@ -0,0 +1,19 @@
+from netbox.tests.dummy_plugin.graphql import DummyModelType
+from netbox.tests.dummy_plugin.models import DummyModel
+from utilities.testing import APIViewTestCases
+
+
+class DummyModelGraphQLTestCase(APIViewTestCases.GraphQLTestCase):
+    model = DummyModel
+    type_class = DummyModelType
+    graphql_base_name = 'dummymodel'
+    graphql_auto_filter_required = False
+    graphql_object_permission_assertions = False
+
+    @classmethod
+    def setUpTestData(cls):
+        DummyModel.objects.bulk_create((
+            DummyModel(name='Dummy 1', number=1),
+            DummyModel(name='Dummy 2', number=2),
+            DummyModel(name='Dummy 3', number=3),
+        ))

+ 43 - 0
netbox/netbox/tests/test_authentication.py

@@ -1,4 +1,5 @@
 import datetime
+from unittest.mock import MagicMock
 
 from django.conf import settings
 from django.contrib.messages.storage.fallback import FallbackStorage
@@ -10,6 +11,7 @@ from social_core.exceptions import AuthFailed
 
 from core.models import ObjectType
 from dcim.models import Rack, Site
+from netbox.authentication.misc import _mirror_groups
 from netbox.middleware import SocialAuthExceptionMiddleware
 from users.constants import TOKEN_PREFIX
 from users.models import Group, ObjectPermission, Token, User
@@ -517,6 +519,47 @@ class ExternalAuthenticationTestCase(TestCase):
         )
 
 
+class LDAPMirrorGroupsTestCase(TestCase):
+    """
+    Test the custom _mirror_groups() patched onto django-auth-ldap's _LDAPUser.
+    """
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.user = User.objects.create(username='ldapuser')
+        Group.objects.create(name='Group 1')
+
+    def _build_ldap_user(self, group_names):
+        """
+        Construct a mock _LDAPUser whose LDAP group search returns the given names.
+        """
+        ldap_user = MagicMock()
+        ldap_user._user = self.user
+        ldap_user._get_groups.return_value.get_group_names.return_value = group_names
+        # Disable allow/deny list handling
+        ldap_user.settings.MIRROR_GROUPS_EXCEPT = None
+        ldap_user.settings.MIRROR_GROUPS = None
+        return ldap_user
+
+    def test_mirror_groups_ignores_empty_names(self):
+        """
+        An LDAP group search returning an empty or null name must not attempt to
+        create a Group with a null name (see #21310).
+        """
+        ldap_user = self._build_ldap_user({'Group 1', '', None})
+
+        _mirror_groups(ldap_user)
+
+        # No group with a null or empty name should have been created
+        self.assertFalse(Group.objects.filter(name__isnull=True).exists())
+        self.assertFalse(Group.objects.filter(name='').exists())
+        # The user should be mirrored into the one valid, matching group
+        self.assertListEqual(
+            ['Group 1'],
+            list(self.user.groups.values_list('name', flat=True))
+        )
+
+
 class ObjectPermissionAPIViewTestCase(TestCase):
     client_class = APIClient
 

+ 5 - 1
netbox/netbox/tests/test_graphql.py

@@ -15,7 +15,7 @@ from extras.models import TableConfig, Tag
 from netbox.graphql.scalars import BigInt, BigIntScalar
 from netbox.graphql.schema import Query, get_schema_extensions, schema
 from utilities.tables import get_table_for_model
-from utilities.testing import APITestCase, TestCase, disable_warnings
+from utilities.testing import APITestCase, APIViewTestCases, TestCase, disable_warnings
 
 
 class GraphQLTestCase(TestCase):
@@ -507,6 +507,10 @@ class GraphQLAPITestCase(APITestCase):
         self.assertEqual(data['errors'][0]['message'], 'Cannot specify both `start` and `offset` in pagination.')
 
 
+class GraphQLSchemaCoverageTestCase(APIViewTestCases.GraphQLSchemaCoverageTestCase):
+    pass
+
+
 class JSONPathValidationTestCase(TestCase):
     """Unit tests for _validate_json_path (VM-323 security fix)."""
 

+ 158 - 0
netbox/netbox/tests/test_middleware.py

@@ -0,0 +1,158 @@
+import json
+from contextlib import contextmanager
+from types import SimpleNamespace
+from unittest.mock import Mock, patch
+
+from django.core.signals import got_request_exception
+from django.db.utils import InternalError
+from django.test import RequestFactory, override_settings
+from django.urls import reverse
+from rest_framework import status
+
+from netbox.middleware import CoreMiddleware, MaintenanceModeMiddleware
+from utilities.testing import TestCase
+
+
+class CoreMiddlewareTestCase(TestCase):
+
+    def setUp(self):
+        super().setUp()
+
+        self.factory = RequestFactory()
+        self.middleware = CoreMiddleware(lambda request: None)
+        self.maintenance_mode_middleware = MaintenanceModeMiddleware(lambda request: None)
+
+    @contextmanager
+    def capture_request_exception_signal(self):
+        captured_requests = []
+
+        def receiver(sender, request, **kwargs):
+            captured_requests.append(request)
+
+        got_request_exception.connect(receiver, sender=CoreMiddleware, weak=False)
+
+        try:
+            yield captured_requests
+        finally:
+            got_request_exception.disconnect(receiver, sender=CoreMiddleware)
+
+    def process_runtime_error(self, request, message='Test exception'):
+        """
+        Call CoreMiddleware.process_exception() from inside an active exception
+        handler. handle_rest_api_exception() uses sys.exc_info(), so calling this
+        inside an except block is important for the JSON response body.
+        """
+        try:
+            raise RuntimeError(message)
+        except RuntimeError as exc:
+            return self.middleware.process_exception(request, exc)
+
+    def process_internal_error(self, request, message='Test database error'):
+        """
+        Call MaintenanceModeMiddleware.process_exception() from inside an active
+        exception handler with an InternalError (the maintenance-mode trigger).
+        """
+        try:
+            raise InternalError(message)
+        except InternalError as exc:
+            return self.maintenance_mode_middleware.process_exception(request, exc)
+
+    def assert_json_500_response(self, response, *, error=None, exception=None):
+        self.assertIsNotNone(response)
+        self.assertHttpStatus(response, status.HTTP_500_INTERNAL_SERVER_ERROR)
+        self.assertEqual(response.headers['Content-Type'], 'application/json')
+
+        data = json.loads(response.content)
+
+        self.assertIn('error', data)
+        self.assertIn('exception', data)
+        self.assertIn('netbox_version', data)
+        self.assertIn('python_version', data)
+
+        if error is not None:
+            self.assertEqual(data['error'], error)
+
+        if exception is not None:
+            self.assertEqual(data['exception'], exception)
+
+    @override_settings(DEBUG=False)
+    def test_process_exception_handles_rest_api_request(self):
+        request = self.factory.get(reverse('api-root'))
+
+        with self.capture_request_exception_signal() as captured_requests:
+            response = self.process_runtime_error(request, 'Simulated REST API error')
+
+        self.assert_json_500_response(response, error='Simulated REST API error', exception='RuntimeError')
+        self.assertEqual(captured_requests, [request])
+
+    @override_settings(DEBUG=False)
+    def test_process_exception_handles_graphql_json_request(self):
+        request = self.factory.post(
+            reverse('graphql'),
+            data='{"query": "{ __typename }"}',
+            content_type='application/json',
+        )
+
+        with self.capture_request_exception_signal() as captured_requests:
+            response = self.process_runtime_error(request, 'Simulated GraphQL error')
+
+        self.assert_json_500_response(response, error='Simulated GraphQL error', exception='RuntimeError')
+        self.assertEqual(captured_requests, [request])
+
+    @override_settings(DEBUG=False)
+    def test_process_exception_does_not_handle_graphql_request_without_json_content_type(self):
+        request = self.factory.get(reverse('graphql'))
+
+        response = self.process_runtime_error(request, 'Simulated GraphiQL error')
+
+        self.assertIsNone(response)
+
+    @override_settings(DEBUG=False)
+    def test_process_exception_does_not_handle_non_api_request(self):
+        request = self.factory.get('/login/')
+
+        response = self.process_runtime_error(request, 'Simulated UI error')
+
+        self.assertIsNone(response)
+
+    @override_settings(DEBUG=True)
+    def test_process_exception_does_not_handle_api_requests_in_debug_mode(self):
+        requests = (
+            self.factory.get(reverse('api-root')),
+            self.factory.post(
+                reverse('graphql'),
+                data='{"query": "{ __typename }"}',
+                content_type='application/json',
+            ),
+        )
+
+        for request in requests:
+            with self.subTest(path=request.path_info):
+                response = self.process_runtime_error(request, 'Debug exception')
+
+                self.assertIsNone(response)
+
+    def test_maintenance_mode_handles_rest_api_request(self):
+        request = self.factory.get(reverse('api-root'))
+
+        with patch('netbox.middleware.get_config', return_value=SimpleNamespace(MAINTENANCE_MODE=True)):
+            response = self.process_internal_error(request, 'Simulated maintenance mode REST API error')
+
+        self.assert_json_500_response(response)
+
+    def test_maintenance_mode_handles_graphql_json_request(self):
+        request = self.factory.post(
+            reverse('graphql'),
+            data='{"query": "{ __typename }"}',
+            content_type='application/json',
+        )
+
+        # With the fix, is_graphql_request short-circuits to the JSON handler before the
+        # messages/redirect path. Mock message storage so that if the fix regresses, the
+        # test fails on response shape instead of erroring on absent message middleware.
+        request._messages = Mock()
+
+        with patch('netbox.middleware.get_config', return_value=SimpleNamespace(MAINTENANCE_MODE=True)):
+            response = self.process_internal_error(request, 'Simulated maintenance mode GraphQL error')
+
+        self.assert_json_500_response(response)

+ 4 - 4
netbox/netbox/tests/test_views.py

@@ -124,8 +124,8 @@ class MediaViewTestCase(TestCase):
         with patch('netbox.views.misc.serve', return_value=HttpResponse(status=200)):
             response = self.client.get(url)
         self.assertHttpStatus(response, 200)
-        self.assertEqual(response['Content-Disposition'], 'attachment')
-        self.assertEqual(response['X-Content-Type-Options'], 'nosniff')
+        self.assertEqual(response['Content-Security-Policy'], "sandbox; default-src 'none'")
+        self.assertEqual(response['X-Content-Type-Options'], "nosniff")
 
     def test_image_attachment_without_permission(self):
         url = reverse('media', kwargs={'path': self.image_attachment.image.name})
@@ -145,8 +145,8 @@ class MediaViewTestCase(TestCase):
         with patch('netbox.views.misc.serve', return_value=HttpResponse(status=200)):
             response = self.client.get(url)
         self.assertHttpStatus(response, 200)
-        self.assertEqual(response['Content-Disposition'], 'attachment')
-        self.assertEqual(response['X-Content-Type-Options'], 'nosniff')
+        self.assertEqual(response['Content-Security-Policy'], "sandbox; default-src 'none'")
+        self.assertEqual(response['X-Content-Type-Options'], "nosniff")
 
     def test_device_type_without_permission(self):
         url = reverse('media', kwargs={'path': self.device_type.front_image.name})

+ 2 - 2
netbox/netbox/views/misc.py

@@ -159,6 +159,6 @@ class MediaView(TokenConditionalLoginRequiredMixin, View):
                 raise Http404
 
         response = serve(request, path, document_root=settings.MEDIA_ROOT)
-        response['Content-Disposition'] = 'attachment'
-        response['X-Content-Type-Options'] = 'nosniff'
+        response['Content-Security-Policy'] = "sandbox; default-src 'none'"
+        response['X-Content-Type-Options'] = "nosniff"
         return response

+ 0 - 1
netbox/project-static/.prettierrc

@@ -4,7 +4,6 @@
   "tabWidth": 2,
   "singleQuote": true,
   "bracketSpacing": true,
-  "jsxBracketSameLine": false,
   "useTabs": false,
   "arrowParens": "avoid",
   "trailingComma": "all"

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
netbox/project-static/dist/netbox.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
netbox/project-static/dist/netbox.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 5 - 5
netbox/project-static/package.json

@@ -43,17 +43,17 @@
     "@types/bootstrap": "5.2.11",
     "@types/cookie": "^1.0.0",
     "@types/node": "^24.10.1",
-    "@typescript-eslint/eslint-plugin": "^8.61.1",
-    "@typescript-eslint/parser": "^8.61.1",
+    "@typescript-eslint/eslint-plugin": "^8.62.1",
+    "@typescript-eslint/parser": "^8.62.1",
     "esbuild": "^0.28.1",
     "esbuild-sass-plugin": "^3.7.0",
-    "eslint": "^10.5.0",
+    "eslint": "^10.6.0",
     "eslint-config-prettier": "^10.1.8",
     "eslint-import-resolver-typescript": "^4.4.5",
     "eslint-plugin-import": "^2.32.0",
     "eslint-plugin-prettier": "^5.5.6",
-    "globals": "^17.5.0",
-    "prettier": "^3.8.4",
+    "globals": "^17.7.0",
+    "prettier": "^3.9.4",
     "typescript": "^5.9.3"
   },
   "resolutions": {

+ 1 - 1
netbox/project-static/src/forms/savedFiltersSelect.ts

@@ -22,7 +22,7 @@ function handleSavedFilterChange(event: Event): void {
 export function initSavedFilterSelect(): void {
   const divResults = document.getElementById('results');
   if (isTruthy(divResults)) {
-    const savedFilterSelect = document.getElementById('id_filter_id');
+    const savedFilterSelect = document.getElementById('saved-filter-select');
     if (isTruthy(savedFilterSelect)) {
       savedFilterSelect.addEventListener('change', handleSavedFilterChange);
     }

+ 12 - 0
netbox/project-static/src/select/classes/netboxTomSelect.ts

@@ -18,6 +18,18 @@ import TomSelect from 'tom-select';
  * NetBox issue:  https://github.com/netbox-community/netbox/issues/20077
  */
 export class NetBoxTomSelect extends TomSelect {
+  setup(): void {
+    super.setup();
+
+    // After TomSelect takes over, the original <select> is visually hidden via the
+    // `ts-hidden-accessible` class and made unfocusable (tabindex=-1), but it remains in the
+    // accessibility tree. Screen readers (e.g. JAWS) then announce a stray listbox/combobox for
+    // every enhanced field. The TomSelect-rendered control already exposes an accessible
+    // combobox, so hide the redundant native element from assistive technology.
+    // See https://github.com/netbox-community/netbox/issues/22530
+    this.input.setAttribute('aria-hidden', 'true');
+  }
+
   focus(): void {
     if (this.isDisabled || this.isReadOnly) return;
 

+ 15 - 6
netbox/project-static/styles/transitional/_navigation.scss

@@ -1,5 +1,13 @@
 // Navbar and light theme styling
 .navbar-vertical.navbar-expand-lg {
+  // Render the <button> menu headings identically to the surrounding nav links
+  .navbar-collapse .nav-item.dropdown > button.nav-link {
+    width: 100%;
+    background-color: transparent;
+    border: 0;
+    text-align: left;
+  }
+
   // Adjust hover color & style for menu items
   .navbar-collapse {
     .nav-link-icon,
@@ -13,21 +21,22 @@
     .dropdown-menu {
       // Adjust hover color & style for menu items
       .dropdown-item {
-        a {
+        > a {
           color: $rich-black;
         }
-        .btn-group {
+        .dropdown-item-buttons {
           visibility: hidden;
         }
 
         // Style menu item hover/active state
         &:hover,
-        &.active {
+        &.active,
+        &:focus-within {
           background-color: var(--tblr-navbar-active-bg);
-          a {
+          > a {
             text-decoration: none;
           }
-          .btn-group {
+          .dropdown-item-buttons {
             visibility: visible;
           }
         }
@@ -98,7 +107,7 @@ html[data-bs-theme='dark'] .navbar-vertical.navbar-expand-lg {
 
   // Adjust hover color & style for menu items
   .dropdown-item {
-    a {
+    > a {
       color: white !important;
     }
     &.active,

+ 75 - 75
netbox/project-static/yarn.lock

@@ -917,100 +917,100 @@
   dependencies:
     "@types/estree" "*"
 
-"@typescript-eslint/eslint-plugin@^8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz#6e4b7fee21f1983308e9e9b634ecbaf702c86006"
-  integrity sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==
+"@typescript-eslint/eslint-plugin@^8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz#1736dcdca6cae3359d818456a47d18b674761f7f"
+  integrity sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==
   dependencies:
     "@eslint-community/regexpp" "^4.12.2"
-    "@typescript-eslint/scope-manager" "8.61.1"
-    "@typescript-eslint/type-utils" "8.61.1"
-    "@typescript-eslint/utils" "8.61.1"
-    "@typescript-eslint/visitor-keys" "8.61.1"
+    "@typescript-eslint/scope-manager" "8.62.1"
+    "@typescript-eslint/type-utils" "8.62.1"
+    "@typescript-eslint/utils" "8.62.1"
+    "@typescript-eslint/visitor-keys" "8.62.1"
     ignore "^7.0.5"
     natural-compare "^1.4.0"
     ts-api-utils "^2.5.0"
 
-"@typescript-eslint/parser@^8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.61.1.tgz#881fba60b50636249cdeea2e547bf75715254c72"
-  integrity sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==
+"@typescript-eslint/parser@^8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.62.1.tgz#d3f7ba18f1bf78bfb7256fea021d1927b48e7080"
+  integrity sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==
   dependencies:
-    "@typescript-eslint/scope-manager" "8.61.1"
-    "@typescript-eslint/types" "8.61.1"
-    "@typescript-eslint/typescript-estree" "8.61.1"
-    "@typescript-eslint/visitor-keys" "8.61.1"
+    "@typescript-eslint/scope-manager" "8.62.1"
+    "@typescript-eslint/types" "8.62.1"
+    "@typescript-eslint/typescript-estree" "8.62.1"
+    "@typescript-eslint/visitor-keys" "8.62.1"
     debug "^4.4.3"
 
-"@typescript-eslint/project-service@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.61.1.tgz#fcd9739964a40867eed55f1ac318d3909f24b4af"
-  integrity sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==
+"@typescript-eslint/project-service@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.62.1.tgz#78d880eb1cf6859b5ec263d04f95403e9f90ae47"
+  integrity sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==
   dependencies:
-    "@typescript-eslint/tsconfig-utils" "^8.61.1"
-    "@typescript-eslint/types" "^8.61.1"
+    "@typescript-eslint/tsconfig-utils" "^8.62.1"
+    "@typescript-eslint/types" "^8.62.1"
     debug "^4.4.3"
 
-"@typescript-eslint/scope-manager@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz#2479921a40fdb0afa18f5838fae6167264b417b2"
-  integrity sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==
+"@typescript-eslint/scope-manager@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz#7ee65e9a6eb3ccdc4816593a4ff38840306de88a"
+  integrity sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==
   dependencies:
-    "@typescript-eslint/types" "8.61.1"
-    "@typescript-eslint/visitor-keys" "8.61.1"
+    "@typescript-eslint/types" "8.62.1"
+    "@typescript-eslint/visitor-keys" "8.62.1"
 
-"@typescript-eslint/tsconfig-utils@8.61.1", "@typescript-eslint/tsconfig-utils@^8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz#ca88080e0cf191d49516d7f300b67aa090d2254f"
-  integrity sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==
+"@typescript-eslint/tsconfig-utils@8.62.1", "@typescript-eslint/tsconfig-utils@^8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz#e2b5f24fe721044189cb7e81117c96d75979d627"
+  integrity sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==
 
-"@typescript-eslint/type-utils@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz#8fa18f453ee140893b47d339d1a6b64cac9b08a1"
-  integrity sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==
+"@typescript-eslint/type-utils@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz#ebd30b13bacb13070917259a23309cf644121f9a"
+  integrity sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==
   dependencies:
-    "@typescript-eslint/types" "8.61.1"
-    "@typescript-eslint/typescript-estree" "8.61.1"
-    "@typescript-eslint/utils" "8.61.1"
+    "@typescript-eslint/types" "8.62.1"
+    "@typescript-eslint/typescript-estree" "8.62.1"
+    "@typescript-eslint/utils" "8.62.1"
     debug "^4.4.3"
     ts-api-utils "^2.5.0"
 
-"@typescript-eslint/types@8.61.1", "@typescript-eslint/types@^8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.61.1.tgz#0c51f518e4e6848371a1c988e859d59eb7522d5a"
-  integrity sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==
+"@typescript-eslint/types@8.62.1", "@typescript-eslint/types@^8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.62.1.tgz#c58be954e483b2fc98275374d5bcb40b99842dc1"
+  integrity sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==
 
-"@typescript-eslint/typescript-estree@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz#febbe70365ac0bf7611262b61b338fc8797965c7"
-  integrity sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==
+"@typescript-eslint/typescript-estree@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz#98c1bb17635d5b026b24193a8d29188ac64380ff"
+  integrity sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==
   dependencies:
-    "@typescript-eslint/project-service" "8.61.1"
-    "@typescript-eslint/tsconfig-utils" "8.61.1"
-    "@typescript-eslint/types" "8.61.1"
-    "@typescript-eslint/visitor-keys" "8.61.1"
+    "@typescript-eslint/project-service" "8.62.1"
+    "@typescript-eslint/tsconfig-utils" "8.62.1"
+    "@typescript-eslint/types" "8.62.1"
+    "@typescript-eslint/visitor-keys" "8.62.1"
     debug "^4.4.3"
     minimatch "^10.2.2"
     semver "^7.7.3"
     tinyglobby "^0.2.15"
     ts-api-utils "^2.5.0"
 
-"@typescript-eslint/utils@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.61.1.tgz#ffd1054de7dd33b7873cd6c6713ec6b0366316d3"
-  integrity sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==
+"@typescript-eslint/utils@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.62.1.tgz#1622b75c7e6df308181dd0b44855dc4228da0457"
+  integrity sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==
   dependencies:
     "@eslint-community/eslint-utils" "^4.9.1"
-    "@typescript-eslint/scope-manager" "8.61.1"
-    "@typescript-eslint/types" "8.61.1"
-    "@typescript-eslint/typescript-estree" "8.61.1"
+    "@typescript-eslint/scope-manager" "8.62.1"
+    "@typescript-eslint/types" "8.62.1"
+    "@typescript-eslint/typescript-estree" "8.62.1"
 
-"@typescript-eslint/visitor-keys@8.61.1":
-  version "8.61.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz#546cf102b4efdb72a9a08e63a1b0d7d745eb66eb"
-  integrity sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==
+"@typescript-eslint/visitor-keys@8.62.1":
+  version "8.62.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz#499657d77ffafb8a99eb1d6c97847ca430234722"
+  integrity sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==
   dependencies:
-    "@typescript-eslint/types" "8.61.1"
+    "@typescript-eslint/types" "8.62.1"
     eslint-visitor-keys "^5.0.0"
 
 "@unrs/resolver-binding-android-arm-eabi@1.11.1":
@@ -1881,10 +1881,10 @@ eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1:
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be"
   integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==
 
-eslint@^10.5.0:
-  version "10.5.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.5.0.tgz#5fca69d6b41fe7e00ba22d4100b2e44efe439ad5"
-  integrity sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==
+eslint@^10.6.0:
+  version "10.6.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.6.0.tgz#e1b4059c582be950c7088c9b55f984738b243c27"
+  integrity sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==
   dependencies:
     "@eslint-community/eslint-utils" "^4.8.0"
     "@eslint-community/regexpp" "^4.12.2"
@@ -2168,10 +2168,10 @@ globals@^14.0.0:
   resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz"
   integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
 
-globals@^17.5.0:
-  version "17.6.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-17.6.0.tgz#0f0be018d5cca8690e6375ead1f65c4bb96191fc"
-  integrity sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==
+globals@^17.7.0:
+  version "17.7.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-17.7.0.tgz#553d55090b4dde8209ec2da42580d6e7e7d8b10d"
+  integrity sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==
 
 globalthis@^1.0.3, globalthis@^1.0.4:
   version "1.0.4"
@@ -2959,10 +2959,10 @@ prettier-linter-helpers@^1.0.1:
   dependencies:
     fast-diff "^1.1.2"
 
-prettier@^3.8.4:
-  version "3.8.4"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.4.tgz#f334f013ac04a96676f24dabc23c1c4ae1bae411"
-  integrity sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==
+prettier@^3.9.4:
+  version "3.9.4"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.9.4.tgz#a9c477cf1614376bd1f6bbc593d8c0d414bcec87"
+  integrity sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==
 
 punycode.js@^2.3.1:
   version "2.3.1"

+ 2 - 2
netbox/release.yaml

@@ -1,3 +1,3 @@
-version: "4.6.3"
+version: "4.6.4"
 edition: "Community"
-published: "2026-06-16"
+published: "2026-06-30"

+ 1 - 1
netbox/templates/core/configrevision_restore.html

@@ -36,7 +36,7 @@
             <th scope="col">{% trans "Parameter" %}</th>
             <th scope="col">{% trans "Current Value" %}</th>
             <th scope="col">{% trans "New Value" %}</th>
-            <th scope="col"></th>
+            <th scope="col" aria-label="{% trans "Changed" %}"></th>
           </tr>
         </thead>
         <tbody>

+ 1 - 1
netbox/templates/dcim/inc/panels/inventory_items.html

@@ -18,7 +18,7 @@
         <th>{% trans "Name" %}</th>
         <th>{% trans "Label" %}</th>
         <th>{% trans "Role" %}</th>
-        <th></th>
+        <th aria-label="{% trans "Actions" %}"></th>
       </tr>
     </thead>
     <tbody>

+ 1 - 1
netbox/templates/dcim/panels/component_inventory_items.html

@@ -8,7 +8,7 @@
         <th>{% trans "Name" %}</th>
         <th>{% trans "Label" %}</th>
         <th>{% trans "Role" %}</th>
-        <th></th>
+        <th aria-label="{% trans "Actions" %}"></th>
       </tr>
     </thead>
     <tbody>

+ 1 - 1
netbox/templates/dcim/panels/interface_wireless.html

@@ -6,7 +6,7 @@
     <table class="table table-hover attr-table">
       <thead>
         <tr class="border-bottom">
-          <th></th>
+          <th aria-label="{% trans "Attribute" %}"></th>
           <th>{% trans "Local" %}</th>
           {% if peer %}
             <th>{% trans "Peer" %}</th>

+ 1 - 1
netbox/templates/dcim/virtualchassis_edit.html

@@ -66,7 +66,7 @@
                     <th>{% trans "Serial" %}</th>
                     <th>{% trans "Position" %}</th>
                     <th>{% trans "Priority" %}</th>
-                    <th></th>
+                    <th aria-label="{% trans "Actions" %}"></th>
                 </tr>
             </thead>
             <tbody>

+ 1 - 1
netbox/templates/extras/inc/script_list_content.html

@@ -33,7 +33,7 @@
               <th>{% trans "Description" %}</th>
               <th>{% trans "Last Run" %}</th>
               <th>{% trans "Status" %}</th>
-              <th></th>
+              <th aria-label="{% trans "Actions" %}"></th>
             </tr>
           </thead>
           <tbody>

+ 2 - 2
netbox/templates/generic/object_list.html

@@ -38,10 +38,10 @@ Context:
 {% block tabs %}
   <ul class="nav nav-tabs" role="tablist">
     <li class="nav-item" role="presentation">
-      <a class="nav-link active" id="object-list-tab" data-bs-toggle="tab" data-bs-target="#object-list" type="button" role="tab" aria-controls="object-list" aria-selected="true">
+      <button class="nav-link active" id="object-list-tab" data-bs-toggle="tab" data-bs-target="#object-list" type="button" role="tab" aria-controls="object-list" aria-selected="true">
         {% trans "Results" %}
         <span class="badge text-bg-secondary total-object-count">{% if table.page.paginator.count %}{{ table.page.paginator.count }}{% else %}{{ total_count|default:"0" }}{% endif %}</span>
-      </a>
+      </button>
     </li>
     {% if filter_form %}
       <li class="nav-item" role="presentation">

+ 11 - 0
netbox/templates/htmx/table.html

@@ -22,6 +22,17 @@
     <div hx-swap-oob="innerHTML:.total-object-count">{{ table.rows|length }}</div>
   {% endif %}
 
+  {# Announce the updated result count to assistive technology #}
+  {% if not table.embedded %}
+    <div hx-swap-oob="innerHTML:#object-list-status">
+      {% blocktrans trimmed count count=table.page.paginator.count %}
+        {{ count }} result found
+      {% plural %}
+        {{ count }} results found
+      {% endblocktrans %}
+    </div>
+  {% endif %}
+
   {# Include the updated "save" link for the table configuration #}
   {% if table.config_params and not table.embedded %}
     <a class="dropdown-item" hx-swap-oob="outerHTML:#table_save_link" href="{% url 'extras:tableconfig_add' %}?{{ table.config_params }}&return_url={{ request.path }}" id="table_save_link">{% trans "Save" %}</a>

+ 7 - 3
netbox/templates/inc/table_controls_htmx.html

@@ -1,6 +1,10 @@
+{% load form_helpers %}
 {% load helpers %}
 {% load i18n %}
 
+{# Live region used to announce updated results (e.g. after a quick search) to assistive technology #}
+<div id="object-list-status" class="visually-hidden" role="status" aria-live="polite"></div>
+
 <div class="row mb-3" id="results">
   <div class="col-auto d-print-none">
     <div class="input-group input-group-flat me-2 quicksearch" hx-disinherit="hx-select hx-swap">
@@ -14,14 +18,14 @@
     </div>
   </div>
 
-  {% if filter_form %}
+  {% if filter_form and filter_form.filter_id %}
     <div class="col-auto d-print-none">
       <div class="input-group">
-        <label for="{{ filter_form.filter_id.id_for_label }}" class="input-group-text">
+        <label for="saved-filter-select" class="input-group-text">
           <i class="mdi mdi-filter" title="{% trans "Saved filter" %}" aria-hidden="true"></i>
           <span class="visually-hidden">{% trans "Saved filter" %}</span>
         </label>
-        {{ filter_form.filter_id }}
+        {% render_field_with_aria filter_form.filter_id element_id="saved-filter-select" %}
       </div>
     </div>
   {% endif %}

+ 1 - 1
netbox/templates/ipam/inc/panels/fhrp_groups.html

@@ -24,7 +24,7 @@
         <th>{% trans "Protocol" %}</th>
         <th>{% trans "Virtual IPs" %}</th>
         <th>{% trans "Priority" %}</th>
-        <th></th>
+        <th aria-label="{% trans "Actions" %}"></th>
       </tr>
     </thead>
     <tbody>

+ 1 - 1
netbox/templates/ipam/panels/fhrp_groups.html

@@ -10,7 +10,7 @@
         <th>{% trans "Protocol" %}</th>
         <th>{% trans "Virtual IPs" %}</th>
         <th>{% trans "Priority" %}</th>
-        <th></th>
+        <th aria-label="{% trans "Actions" %}"></th>
       </tr>
     </thead>
     <tbody>

BIN
netbox/translations/cs/LC_MESSAGES/django.mo


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 163 - 158
netbox/translations/cs/LC_MESSAGES/django.po


BIN
netbox/translations/da/LC_MESSAGES/django.mo


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.