Quellcode durchsuchen

Merge branch 'develop' into feature

Jeremy Stretch vor 1 Jahr
Ursprung
Commit
e370cadcef
55 geänderte Dateien mit 3187 neuen und 2732 gelöschten Zeilen
  1. 1 1
      .github/ISSUE_TEMPLATE/01-feature_request.yaml
  2. 1 1
      .github/ISSUE_TEMPLATE/02-bug_report.yaml
  3. 44 0
      .pre-commit-config.yaml
  4. 3 0
      contrib/generated_schema.json
  5. 22 17
      docs/development/getting-started.md
  6. 6 1
      docs/release-notes/version-4.1.md
  7. 8 0
      netbox/dcim/models/cables.py
  8. 7 0
      netbox/dcim/models/devices.py
  9. 43 0
      netbox/dcim/tests/test_cablepaths.py
  10. 0 10
      netbox/netbox/graphql/views.py
  11. 0 0
      netbox/project-static/dist/netbox.css
  12. 0 0
      netbox/project-static/dist/netbox.js
  13. 0 0
      netbox/project-static/dist/netbox.js.map
  14. 2 2
      netbox/project-static/package.json
  15. 42 0
      netbox/project-static/src/buttons/floatBulk.ts
  16. 2 0
      netbox/project-static/src/buttons/index.ts
  17. 30 0
      netbox/project-static/styles/custom/_misc.scss
  18. 103 9
      netbox/project-static/yarn.lock
  19. 2 2
      netbox/release.yaml
  20. 2 2
      netbox/templates/generic/bulk_edit.html
  21. 3 3
      netbox/templates/generic/object_edit.html
  22. 1 1
      netbox/templates/generic/object_list.html
  23. 8 8
      netbox/templates/inc/filter_list.html
  24. 3 3
      netbox/templates/login.html
  25. BIN
      netbox/translations/cs/LC_MESSAGES/django.mo
  26. 197 184
      netbox/translations/cs/LC_MESSAGES/django.po
  27. BIN
      netbox/translations/da/LC_MESSAGES/django.mo
  28. 192 180
      netbox/translations/da/LC_MESSAGES/django.po
  29. BIN
      netbox/translations/de/LC_MESSAGES/django.mo
  30. 193 181
      netbox/translations/de/LC_MESSAGES/django.po
  31. 155 148
      netbox/translations/en/LC_MESSAGES/django.po
  32. BIN
      netbox/translations/es/LC_MESSAGES/django.mo
  33. 192 180
      netbox/translations/es/LC_MESSAGES/django.po
  34. BIN
      netbox/translations/fr/LC_MESSAGES/django.mo
  35. 192 180
      netbox/translations/fr/LC_MESSAGES/django.po
  36. BIN
      netbox/translations/it/LC_MESSAGES/django.mo
  37. 192 180
      netbox/translations/it/LC_MESSAGES/django.po
  38. BIN
      netbox/translations/ja/LC_MESSAGES/django.mo
  39. 192 180
      netbox/translations/ja/LC_MESSAGES/django.po
  40. BIN
      netbox/translations/nl/LC_MESSAGES/django.mo
  41. 192 179
      netbox/translations/nl/LC_MESSAGES/django.po
  42. BIN
      netbox/translations/pl/LC_MESSAGES/django.mo
  43. 192 180
      netbox/translations/pl/LC_MESSAGES/django.po
  44. BIN
      netbox/translations/pt/LC_MESSAGES/django.mo
  45. 192 180
      netbox/translations/pt/LC_MESSAGES/django.po
  46. BIN
      netbox/translations/ru/LC_MESSAGES/django.mo
  47. 193 181
      netbox/translations/ru/LC_MESSAGES/django.po
  48. BIN
      netbox/translations/tr/LC_MESSAGES/django.mo
  49. 192 180
      netbox/translations/tr/LC_MESSAGES/django.po
  50. BIN
      netbox/translations/uk/LC_MESSAGES/django.mo
  51. 186 174
      netbox/translations/uk/LC_MESSAGES/django.po
  52. BIN
      netbox/translations/zh/LC_MESSAGES/django.mo
  53. 192 180
      netbox/translations/zh/LC_MESSAGES/django.po
  54. 5 5
      requirements.txt
  55. 5 0
      scripts/git-hooks/pre-commit

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

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

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

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

+ 44 - 0
.pre-commit-config.yaml

@@ -0,0 +1,44 @@
+repos:
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  rev: v0.6.9
+  hooks:
+    - id: ruff
+      name: "Ruff linter"
+      args: [ netbox/ ]
+- repo: local
+  hooks:
+    - id: django-check
+      name: "Django system check"
+      description: "Run Django's internal check for common problems"
+      entry: python netbox/manage.py check
+      language: system
+      pass_filenames: false
+      types: [python]
+    - id: django-makemigrations
+      name: "Django migrations check"
+      description: "Check for any missing Django migrations"
+      entry: python netbox/manage.py makemigrations --check
+      language: system
+      pass_filenames: false
+      types: [python]
+    - id: mkdocs-build
+      name: "Build documentation"
+      description: "Build the documentation with mkdocs"
+      files: 'docs/'
+      entry: mkdocs build
+      language: system
+      pass_filenames: false
+    - id: yarn-validate
+      name: "Yarn validate"
+      description: "Check UI ESLint, TypeScript, and Prettier compliance"
+      files: 'netbox/project-static/'
+      entry: yarn --cwd netbox/project-static validate
+      language: system
+      pass_filenames: false
+    - id: verify-bundles
+      name: "Verify static asset bundles"
+      description: "Ensure that any modified static assets have been compiled"
+      files: 'netbox/project-static/'
+      entry: scripts/verify-bundles.sh
+      language: system
+      pass_filenames: false

+ 3 - 0
contrib/generated_schema.json

@@ -12,6 +12,9 @@
                 "left-to-right",
                 "right-to-left",
                 "side-to-rear",
+                "rear-to-side",
+                "bottom-to-top",
+                "top-to-bottom",
                 "passive",
                 "mixed"
             ]

+ 22 - 17
docs/development/getting-started.md

@@ -62,22 +62,7 @@ $issue-$description
 
 The description should be just two or three words to imply the focus of the work being performed. For example, bug #1234 to fix a TypeError exception when creating a device might be named `1234-device-typerror`. This ensures that branches are always follow some logical ordering (e.g. when running `git branch -a`) and helps other developers quickly identify the purpose of each.
 
-### 3. Enable Pre-Commit Hooks
-
-NetBox ships with a [git pre-commit hook](https://githooks.com/) script that automatically checks for style compliance and missing database migrations prior to committing changes. This helps avoid erroneous commits that result in CI test failures. You are encouraged to enable it by creating a link to `scripts/git-hooks/pre-commit`:
-
-```no-highlight
-cd .git/hooks/
-ln -s ../../scripts/git-hooks/pre-commit
-```
-For the pre-commit hooks to work, you will also need to install the [ruff](https://docs.astral.sh/ruff/) linter:
-
-```no-highlight
-python -m pip install ruff
-```
-...and set up the yarn packages as shown in the [Web UI Development Guide](web-ui.md)
-
-### 4. Create a Python Virtual Environment
+### 3. Create a Python Virtual Environment
 
 A [virtual environment](https://docs.python.org/3/tutorial/venv.html) (or "venv" for short) is like a container for a set of Python packages. These allow you to build environments suited to specific projects without interfering with system packages or other projects. When installed per the documentation, NetBox uses a virtual environment in production.
 
@@ -101,7 +86,7 @@ source ~/.venv/netbox/bin/activate
 
 Notice that the console prompt changes to indicate the active environment. This updates the necessary system environment variables to ensure that any Python scripts are run within the virtual environment.
 
-### 5. Install Required Packages
+### 4. Install Required Packages
 
 With the virtual environment activated, install the project's required Python packages using the `pip` module. Required packages are defined in `requirements.txt`. Each line in this file specifies the name and specific version of a required package.
 
@@ -109,6 +94,26 @@ With the virtual environment activated, install the project's required Python pa
 python -m pip install -r requirements.txt
 ```
 
+### 5. Install Pre-Commit
+
+NetBox uses [`pre-commit`](https://pre-commit.com/) to automatically validate code when commiting new changes. This includes the following operations:
+
+* Run the `ruff` Python linter
+* Run Django's internal system check
+* Check for missing database migrations
+* Validate any changes to the documentation with `mkdocs`
+* Validate Typescript & Sass styling with `yarn`
+* Ensure that any modified static front end assets have been recompiled
+
+Enable `pre-commit` with the following commands _prior_ to commiting any changes:
+
+```no-highlight
+python -m pip install ruff pre-commit
+pre-commit install
+```
+
+You may also need to set up the yarn packages as shown in the [Web UI Development Guide](web-ui.md).
+
 ### 6. Configure NetBox
 
 Within the `netbox/netbox/` directory, copy `configuration_example.py` to `configuration.py` and update the following parameters:

+ 6 - 1
docs/release-notes/version-4.1.md

@@ -1,11 +1,12 @@
 # NetBox v4.1
 
-## v4.1.4 (FUTURE)
+## v4.1.4 (2024-10-15)
 
 ### Enhancements
 
 * [#11671](https://github.com/netbox-community/netbox/issues/11671) - Display device's rack position in cable traces
 * [#15829](https://github.com/netbox-community/netbox/issues/15829) - Rename Microsoft Azure AD SSO backend to Microsoft Entra ID
+* [#16009](https://github.com/netbox-community/netbox/issues/16009) - Float form & bulk operation buttons within UI
 * [#17079](https://github.com/netbox-community/netbox/issues/17079) - Introduce additional choices for device airflow direction
 * [#17216](https://github.com/netbox-community/netbox/issues/17216) - Add EVPN-VPWS L2VPN type
 * [#17655](https://github.com/netbox-community/netbox/issues/17655) - Limit the display of tagged VLANs within interface tables
@@ -14,12 +15,16 @@
 ### Bug Fixes
 
 * [#16024](https://github.com/netbox-community/netbox/issues/16024) - Fix AND/OR filtering in GraphQL API for selection fields
+* [#17400](https://github.com/netbox-community/netbox/issues/17400) - Fix cable tracing across split paths
 * [#17562](https://github.com/netbox-community/netbox/issues/17562) - Fix GraphQL API query support for custom field choices
 * [#17566](https://github.com/netbox-community/netbox/issues/17566) - Fix AttributeError exception resulting from background jobs with no associated object type
+* [#17614](https://github.com/netbox-community/netbox/issues/17614) - Disallow removal of a master device from its virtual chassis
 * [#17636](https://github.com/netbox-community/netbox/issues/17636) - Fix filtering of related objects when adding a power port, rear port, or inventory item template to a device type
+* [#17644](https://github.com/netbox-community/netbox/issues/17644) - Correct sizing of logo & SSO icons on login page
 * [#17648](https://github.com/netbox-community/netbox/issues/17648) - Fix AttributeError exception when attempting to delete a background job under certain conditions
 * [#17663](https://github.com/netbox-community/netbox/issues/17663) - Fix extended lookups for choice field filters
 * [#17671](https://github.com/netbox-community/netbox/issues/17671) - Fix the display of rack types in global search results
+* [#17713](https://github.com/netbox-community/netbox/issues/17713) - Fix UnboundLocalError exception when attempting to sync data source in parallel
 
 ---
 

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

@@ -662,6 +662,14 @@ class CablePath(models.Model):
                         rear_port_id=remote_terminations[0].pk,
                         rear_port_position__in=position_stack.pop()
                     )
+                # If all rear ports have a single position, we can just get the front ports
+                elif all([rp.positions == 1 for rp in remote_terminations]):
+                    front_ports = FrontPort.objects.filter(rear_port_id__in=[rp.pk for rp in remote_terminations])
+
+                    if len(front_ports) != len(remote_terminations):
+                        # Some rear ports does not have a front port
+                        is_split = True
+                        break
                 else:
                     # No position indicated: path has split, so we stop at the RearPorts
                     is_split = True

+ 7 - 0
netbox/dcim/models/devices.py

@@ -966,6 +966,13 @@ class Device(
                 'vc_position': _("A device assigned to a virtual chassis must have its position defined.")
             })
 
+        if hasattr(self, 'vc_master_for') and self.vc_master_for and self.vc_master_for != self.virtual_chassis:
+            raise ValidationError({
+                'virtual_chassis': _('Device cannot be removed from virtual chassis {virtual_chassis} because it is currently designated as its master.').format(
+                    virtual_chassis=self.vc_master_for
+                )
+            })
+
     def _instantiate_components(self, queryset, bulk_create=True):
         """
         Instantiate components for the device from the specified component templates.

+ 43 - 0
netbox/dcim/tests/test_cablepaths.py

@@ -2060,6 +2060,49 @@ class CablePathTestCase(TestCase):
         # Test SVG generation
         CableTraceSVG(interface1).render()
 
+    def test_222_single_path_via_multiple_singleposition_rear_ports(self):
+        """
+        [IF1] --C1-- [FP1] [RP1] --C2-- [IF2]
+                     [FP2] [RP2]
+        """
+        interface1 = Interface.objects.create(device=self.device, name='Interface 1')
+        interface2 = Interface.objects.create(device=self.device, name='Interface 2')
+        rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=1)
+        rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=1)
+        frontport1 = FrontPort.objects.create(
+            device=self.device, name='Front Port 1', rear_port=rearport1, rear_port_position=1
+        )
+        frontport2 = FrontPort.objects.create(
+            device=self.device, name='Front Port 2', rear_port=rearport2, rear_port_position=1
+        )
+
+        cable1 = Cable(
+            a_terminations=[interface1],
+            b_terminations=[frontport1, frontport2]
+        )
+        cable1.save()
+        self.assertEqual(CablePath.objects.count(), 1)
+
+        cable2 = Cable(
+            a_terminations=[rearport1, rearport2],
+            b_terminations=[interface2]
+        )
+        cable2.save()
+        self.assertEqual(CablePath.objects.count(), 2)
+
+        self.assertPathExists(
+            (interface1, cable1, (frontport1, frontport2), (rearport1, rearport2), cable2, interface2),
+            is_complete=True
+        )
+        self.assertPathExists(
+            (interface2, cable2, (rearport1, rearport2), (frontport1, frontport2), cable1, interface1),
+            is_complete=True
+        )
+
+        # Test SVG generation both directions
+        CableTraceSVG(interface1).render()
+        CableTraceSVG(interface2).render()
+
     def test_301_create_path_via_existing_cable(self):
         """
         [IF1] --C1-- [FP1] [RP1] --C2-- [RP2] [FP2] --C3-- [IF2]

+ 0 - 10
netbox/netbox/graphql/views.py

@@ -1,10 +1,6 @@
-import json
-
 from django.conf import settings
 from django.contrib.auth.views import redirect_to_login
 from django.http import HttpResponseNotFound, HttpResponseForbidden
-from django.http import HttpResponse
-from django.template import loader
 from django.urls import reverse
 from django.views.decorators.csrf import csrf_exempt
 from rest_framework.exceptions import AuthenticationFailed
@@ -46,9 +42,3 @@ class NetBoxGraphQLView(GraphQLView):
                 return HttpResponseForbidden("No credentials provided.")
 
         return super().dispatch(request, *args, **kwargs)
-
-    def render_graphql_ide(self, request):
-        template = loader.get_template("graphiql.html")
-        context = {"SUBSCRIPTION_ENABLED": json.dumps(self.subscriptions_enabled)}
-
-        return HttpResponse(template.render(context, request))

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
netbox/project-static/dist/netbox.css


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
netbox/project-static/dist/netbox.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
netbox/project-static/dist/netbox.js.map


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

@@ -29,8 +29,8 @@
     "flatpickr": "4.6.13",
     "gridstack": "10.3.1",
     "htmx.org": "1.9.12",
-    "query-string": "9.1.0",
-    "sass": "1.79.3",
+    "query-string": "9.1.1",
+    "sass": "1.79.5",
     "tom-select": "2.3.1",
     "typeface-inter": "3.18.1",
     "typeface-roboto-mono": "1.1.13"

+ 42 - 0
netbox/project-static/src/buttons/floatBulk.ts

@@ -0,0 +1,42 @@
+import { getElements } from '../util';
+
+/**
+ * Conditionally add and remove a class that will float the button group
+ * based on whether or not items in the list are checked
+ */
+function toggleFloat(): void {
+  const checkedCheckboxes = document.querySelector<HTMLInputElement>(
+    'input[type="checkbox"][name="pk"]:checked',
+  );
+  const buttonGroup = document.querySelector<HTMLDivElement>(
+    'div.form.form-horizontal div.btn-list',
+  );
+  if (!buttonGroup) {
+    return;
+  }
+  const isFloating = buttonGroup.classList.contains('btn-float-group-left');
+  if (checkedCheckboxes !== null && !isFloating) {
+    buttonGroup.classList.add('btn-float-group-left');
+  } else if (checkedCheckboxes === null && isFloating) {
+    buttonGroup.classList.remove('btn-float-group-left');
+  }
+}
+
+/**
+ * Initialize floating bulk buttons.
+ */
+export function initFloatBulk(): void {
+  for (const element of getElements<HTMLInputElement>('input[type="checkbox"][name="pk"]')) {
+    element.addEventListener('change', () => {
+      toggleFloat();
+    });
+  }
+  // Handle the select-all checkbox
+  for (const element of getElements<HTMLInputElement>(
+    'table tr th > input[type="checkbox"].toggle',
+  )) {
+    element.addEventListener('change', () => {
+      toggleFloat();
+    });
+  }
+}

+ 2 - 0
netbox/project-static/src/buttons/index.ts

@@ -3,6 +3,7 @@ import { initDepthToggle } from './depthToggle';
 import { initMoveButtons } from './moveOptions';
 import { initReslug } from './reslug';
 import { initSelectAll } from './selectAll';
+import { initFloatBulk } from './floatBulk';
 import { initSelectMultiple } from './selectMultiple';
 import { initMarkdownPreviews } from './markdownPreview';
 import { initSecretToggle } from './secretToggle';
@@ -14,6 +15,7 @@ export function initButtons(): void {
     initReslug,
     initSelectAll,
     initSelectMultiple,
+    initFloatBulk,
     initMoveButtons,
     initMarkdownPreviews,
     initSecretToggle,

+ 30 - 0
netbox/project-static/styles/custom/_misc.scss

@@ -33,3 +33,33 @@ span.color-label {
 .netbox-edition {
   letter-spacing: .15rem;
 }
+
+// A floating div for form buttons
+.btn-float-group {
+  position: sticky;
+  bottom: 10px;
+  z-index: 2;
+}
+
+.btn-float-group-left {
+  @extend .btn-float-group;
+  float: left;  
+}
+
+.btn-float-group-right {
+  @extend .btn-float-group;
+  float: right;
+}
+
+// Override a transparent background
+.btn-float {
+  --tblr-btn-bg: var(--#{$prefix}bg-surface-tertiary) !important;
+}
+
+.logo {
+  height: 80px;
+}
+
+.sso-icon {
+  height: 24px;
+}

+ 103 - 9
netbox/project-static/yarn.lock

@@ -365,6 +365,89 @@
   resolved "https://registry.yarnpkg.com/@orchidjs/unicode-variants/-/unicode-variants-1.0.4.tgz#6d2f812e3b19545bba2d81caffff1204de9a6a58"
   integrity sha512-NvVBRnZNE+dugiXERFsET1JlKZfM5lJDEpSMilKW4bToYJ7pxf0Zne78xyXB2ny2c2aHfJ6WLnz1AaTNHAmQeQ==
 
+"@parcel/watcher-android-arm64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84"
+  integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==
+
+"@parcel/watcher-darwin-arm64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34"
+  integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==
+
+"@parcel/watcher-darwin-x64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020"
+  integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==
+
+"@parcel/watcher-freebsd-x64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8"
+  integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==
+
+"@parcel/watcher-linux-arm-glibc@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d"
+  integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==
+
+"@parcel/watcher-linux-arm64-glibc@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7"
+  integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==
+
+"@parcel/watcher-linux-arm64-musl@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635"
+  integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==
+
+"@parcel/watcher-linux-x64-glibc@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39"
+  integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==
+
+"@parcel/watcher-linux-x64-musl@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16"
+  integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==
+
+"@parcel/watcher-win32-arm64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc"
+  integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==
+
+"@parcel/watcher-win32-ia32@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7"
+  integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==
+
+"@parcel/watcher-win32-x64@2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf"
+  integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==
+
+"@parcel/watcher@^2.4.1":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8"
+  integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==
+  dependencies:
+    detect-libc "^1.0.3"
+    is-glob "^4.0.3"
+    micromatch "^4.0.5"
+    node-addon-api "^7.0.0"
+  optionalDependencies:
+    "@parcel/watcher-android-arm64" "2.4.1"
+    "@parcel/watcher-darwin-arm64" "2.4.1"
+    "@parcel/watcher-darwin-x64" "2.4.1"
+    "@parcel/watcher-freebsd-x64" "2.4.1"
+    "@parcel/watcher-linux-arm-glibc" "2.4.1"
+    "@parcel/watcher-linux-arm64-glibc" "2.4.1"
+    "@parcel/watcher-linux-arm64-musl" "2.4.1"
+    "@parcel/watcher-linux-x64-glibc" "2.4.1"
+    "@parcel/watcher-linux-x64-musl" "2.4.1"
+    "@parcel/watcher-win32-arm64" "2.4.1"
+    "@parcel/watcher-win32-ia32" "2.4.1"
+    "@parcel/watcher-win32-x64" "2.4.1"
+
 "@pkgr/core@^0.1.0":
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
@@ -1196,6 +1279,11 @@ delegate@^3.1.2:
   resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
   integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
 
+detect-libc@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+  integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
+
 detect-node-es@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
@@ -2205,7 +2293,7 @@ meros@^1.1.4:
   resolved "https://registry.yarnpkg.com/meros/-/meros-1.3.0.tgz#c617d2092739d55286bf618129280f362e6242f2"
   integrity sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==
 
-micromatch@^4.0.4:
+micromatch@^4.0.4, micromatch@^4.0.5:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
   integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
@@ -2247,6 +2335,11 @@ natural-compare@^1.4.0:
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
   integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
 
+node-addon-api@^7.0.0:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
+  integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
+
 normalize-path@^3.0.0, normalize-path@~3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
@@ -2417,10 +2510,10 @@ punycode@^2.1.0:
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
   integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
 
-query-string@9.1.0:
-  version "9.1.0"
-  resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.1.0.tgz#5f12a4653a4ba56021e113b5cf58e56581823e7a"
-  integrity sha512-t6dqMECpCkqfyv2FfwVS1xcB6lgXW/0XZSaKdsCNGYkqMO76AFiJEg4vINzoDKcZa6MS7JX+OHIjwh06K5vczw==
+query-string@9.1.1:
+  version "9.1.1"
+  resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.1.1.tgz#dbfebb4196aeb2919915f2b2b81b91b965cf03a0"
+  integrity sha512-MWkCOVIcJP9QSKU52Ngow6bsAWAPlPK2MludXvcrS2bGZSl+T1qX9MZvRIkqUIkGLJquMJHWfsT6eRqUpp4aWg==
   dependencies:
     decode-uri-component "^0.4.1"
     filter-obj "^5.1.0"
@@ -2563,11 +2656,12 @@ safe-regex-test@^1.0.3:
     es-errors "^1.3.0"
     is-regex "^1.1.4"
 
-sass@1.79.3:
-  version "1.79.3"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.79.3.tgz#7811b000eb68195fe51dea89177e73e7ef7f546f"
-  integrity sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==
+sass@1.79.5:
+  version "1.79.5"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.79.5.tgz#646c627601cd5f84c64f7b1485b9292a313efae4"
+  integrity sha512-W1h5kp6bdhqFh2tk3DsI771MoEJjvrSY/2ihJRJS4pjIyfJCw0nTsxqhnrUzaLMOJjFchj8rOvraI/YUVjtx5g==
   dependencies:
+    "@parcel/watcher" "^2.4.1"
     chokidar "^4.0.0"
     immutable "^4.0.0"
     source-map-js ">=0.6.2 <2.0.0"

+ 2 - 2
netbox/release.yaml

@@ -1,3 +1,3 @@
-version: "4.1.3"
+version: "4.1.4"
 edition: "Community"
-published: "2024-10-02"
+published: "2024-10-15"

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

@@ -102,8 +102,8 @@ Context:
 
       {% endif %}
 
-      <div class="text-end">
-        <a href="{{ return_url }}" class="btn btn-outline-secondary">{% trans "Cancel" %}</a>
+      <div class="btn-float-group-right">
+        <a href="{{ return_url }}" class="btn btn-outline-secondary btn-float">{% trans "Cancel" %}</a>
         <button type="submit" name="_apply" class="btn btn-primary">{% trans "Apply" %}</button>
       </div>
 

+ 3 - 3
netbox/templates/generic/object_edit.html

@@ -67,9 +67,9 @@ Context:
         {% endblock form %}
       </div>
 
-      <div class="text-end my-3">
+      <div class="btn-float-group-right">
         {% block buttons %}
-          <a href="{{ return_url }}" class="btn btn-outline-secondary">{% trans "Cancel" %}</a>
+          <a href="{{ return_url }}" class="btn btn-outline-secondary btn-float">{% trans "Cancel" %}</a>
           {% if object.pk %}
             <button type="submit" name="_update" class="btn btn-primary">
               {% trans "Save" %}
@@ -79,7 +79,7 @@ Context:
               <button type="submit" name="_create" class="btn btn-primary">
                 {% trans "Create" %}
               </button>
-              <button type="submit" name="_addanother" class="btn btn-outline-primary">
+              <button type="submit" name="_addanother" class="btn btn-outline-primary btn-float">
                 {% trans "Create & Add Another" %}
               </button>
             </div>

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

@@ -121,7 +121,7 @@ Context:
           {# /Objects table #}
 
           {# Form buttons #}
-          <div class="btn-list d-print-none mt-2">
+          <div class="btn-list d-print-none">
             {% block bulk_buttons %}
               <div class="bulk-action-buttons">
                 {% if 'bulk_edit' in actions %}

+ 8 - 8
netbox/templates/inc/filter_list.html

@@ -37,13 +37,13 @@
         </div>
       {% endif %}
     </div>
-    <div class="card-footer text-end d-print-none border-0">
-      <button type="button" class="btn btn-outline-danger m-1" data-reset-select>
-        <i class="mdi mdi-backspace"></i> {% trans "Reset" %}
-      </button>
-      <button type="submit" class="btn btn-primary m-1">
-        <i class="mdi mdi-magnify"></i> {% trans "Search" %}
-      </button>
-    </div>
+  </div>
+  <div class="btn-float-group-right me-1">
+    <button type="button" class="btn btn-outline-danger btn-float" data-reset-select>
+      <i class="mdi mdi-backspace"></i> {% trans "Reset" %}
+    </button>
+    <button type="submit" class="btn btn-primary">
+      <i class="mdi mdi-magnify"></i> {% trans "Search" %}
+    </button>
   </div>
 </form>

+ 3 - 3
netbox/templates/login.html

@@ -11,8 +11,8 @@
 
       {# NetBox logo #}
       <div class="text-center mb-4">
-        <img src="{% static 'logo_netbox_dark_teal.svg' %}" alt="{% trans "NetBox Logo" %}" height="80" class="hide-theme-dark">
-        <img src="{% static 'logo_netbox_bright_teal.svg' %}" alt="{% trans "NetBox Logo" %}" height="80" class="hide-theme-light">
+        <img src="{% static 'logo_netbox_dark_teal.svg' %}" alt="{% trans "NetBox Logo" %}" height="80" class="hide-theme-dark logo">
+        <img src="{% static 'logo_netbox_bright_teal.svg' %}" alt="{% trans "NetBox Logo" %}" height="80" class="hide-theme-light logo">
         <div class="netbox-edition fw-semibold">{{ settings.RELEASE.edition }}</div>
       </div>
 
@@ -81,7 +81,7 @@
                 <div class="col">
                   <a href="{{ backend.url }}" class="btn w-100">
                     {% if backend.icon_name %}<i class="mdi mdi-{{ backend.icon_name }}"></i>
-                    {% elif backend.icon_img %}<img src="{{ backend.icon_img }}" height="24" {% if backend.display_name %}class="me-2" {% endif %}/>{% endif %}
+                    {% elif backend.icon_img %}<img src="{{ backend.icon_img }}" height="24"{% if backend.display_name %}class="me-2 sso-icon" {% endif %}/>{% endif %}
                     {{ backend.display_name }}
                   </a>
                 </div>

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


Datei-Diff unterdrückt, da er zu groß ist
+ 197 - 184
netbox/translations/cs/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/da/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 193 - 181
netbox/translations/de/LC_MESSAGES/django.po


Datei-Diff unterdrückt, da er zu groß ist
+ 155 - 148
netbox/translations/en/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/es/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/fr/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/it/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/ja/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 179
netbox/translations/nl/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/pl/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/pt/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 193 - 181
netbox/translations/ru/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/tr/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 186 - 174
netbox/translations/uk/LC_MESSAGES/django.po


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


Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 180
netbox/translations/zh/LC_MESSAGES/django.po


+ 5 - 5
requirements.txt

@@ -1,5 +1,5 @@
 Django==5.1.2
-django-cors-headers==4.4.0
+django-cors-headers==4.5.0
 django-debug-toolbar==4.4.6
 django-filter==24.3
 django-htmx==1.19.0
@@ -20,8 +20,8 @@ feedparser==6.0.11
 gunicorn==23.0.0
 Jinja2==3.1.4
 Markdown==3.7
-mkdocs-material==9.5.39
-mkdocstrings[python-legacy]==0.26.1
+mkdocs-material==9.5.41
+mkdocstrings[python-legacy]==0.26.2
 netaddr==1.3.0
 nh3==0.2.18
 Pillow==10.4.0
@@ -30,8 +30,8 @@ PyYAML==6.0.2
 requests==2.32.3
 social-auth-app-django==5.4.2
 social-auth-core==4.5.4
-strawberry-graphql==0.243.1
+strawberry-graphql==0.246.2
 strawberry-graphql-django==0.48.0
 svgwrite==1.4.3
-tablib==3.6.1
+tablib==3.7.0
 tzdata==2024.2

+ 5 - 0
scripts/git-hooks/pre-commit

@@ -14,6 +14,11 @@ RED='\033[0;31m'
 YELLOW='\033[0;33m'
 NOCOLOR='\033[0m'
 
+printf "${YELLOW}This script is obsolete and will be removed in a future release.\n"
+printf "Please use pre-commit instead:\n"
+printf "  pip install pre-commit\n"
+printf "  pre-commit install${NOCOLOR}\n"
+
 if [ -d ./venv/ ]; then
     VENV="$PWD/venv"
     if [ -e $VENV/bin/python ]; then

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.