diff --git a/.github/ISSUE_TEMPLATE/01-feature_request.yaml b/.github/ISSUE_TEMPLATE/01-feature_request.yaml index 651c26942..ec755cd0c 100644 --- a/.github/ISSUE_TEMPLATE/01-feature_request.yaml +++ b/.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.5 + placeholder: v4.1.7 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/02-bug_report.yaml b/.github/ISSUE_TEMPLATE/02-bug_report.yaml index 2984e3d10..3ae3cbd33 100644 --- a/.github/ISSUE_TEMPLATE/02-bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/02-bug_report.yaml @@ -39,7 +39,7 @@ body: attributes: label: NetBox Version description: What version of NetBox are you currently running? - placeholder: v4.1.5 + placeholder: v4.1.7 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2ad52023e..efbf38932 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,6 +7,9 @@ contact_links: - name: ❓ Discussion url: https://github.com/netbox-community/netbox/discussions about: "If you're just looking for help, try starting a discussion instead." + - name: 👔 Professional Support + url: https://netboxlabs.com/netbox-enterprise/ + about: "Professional support is available for NetBox Enterprise or Cloud." - name: 🌎 Correct a Translation url: https://explore.transifex.com/netbox-community/netbox/ about: "Spot an incorrect translation? You can propose a fix on Transifex." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d77da90e3..aab8bc34f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,11 @@ on: permissions: contents: read +# Add concurrency group to control job running +concurrency: + group: ${{ github.event_name }}-${{ github.ref }}-${{ github.actor }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest diff --git a/.tx/config b/.tx/config new file mode 100755 index 000000000..342331d4e --- /dev/null +++ b/.tx/config @@ -0,0 +1,12 @@ +[main] +host = https://app.transifex.com + +[o:netbox-community:p:netbox:r:9cbf4fcf95b3d92e4ebbf1a5e5d1caee] +file_filter = netbox/translations//LC_MESSAGES/django.po +source_file = netbox/translations/en/LC_MESSAGES/django.po +type = PO +minimum_perc = 0 +resource_name = django.po +replace_edited_strings = false +keep_translations = false + diff --git a/base_requirements.txt b/base_requirements.txt index 2147731e2..3e5bcb0db 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -42,7 +42,7 @@ django-rich # Django integration for RQ (Reqis queuing) # https://github.com/rq/django-rq/blob/master/CHANGELOG.md -django-rq<3.0 +django-rq # Abstraction models for rendering and paginating HTML tables # https://github.com/jieter/django-tables2/blob/master/CHANGELOG.md @@ -118,7 +118,7 @@ requests # rq # https://github.com/rq/rq/blob/master/CHANGES.md -rq<2.0 +rq # Social authentication framework # https://github.com/python-social-auth/social-core/blob/master/CHANGELOG.md diff --git a/contrib/generated_schema.json b/contrib/generated_schema.json index 56ddee50e..639f0df8d 100644 --- a/contrib/generated_schema.json +++ b/contrib/generated_schema.json @@ -329,6 +329,7 @@ "100base-tx", "100base-t1", "1000base-t", + "1000base-lx", "1000base-tx", "2.5gbase-t", "5gbase-t", diff --git a/docs/development/release-checklist.md b/docs/development/release-checklist.md index 7c8c96f39..4e5fdeca8 100644 --- a/docs/development/release-checklist.md +++ b/docs/development/release-checklist.md @@ -90,7 +90,20 @@ This will automatically update the schema file at `contrib/generated_schema.json ### Update & Compile Translations -Updated language translations should be pulled from [Transifex](https://app.transifex.com/netbox-community/netbox/dashboard/) and re-compiled for each new release. Follow the documented process for [updating translated strings](./translations.md#updating-translated-strings) to do this. +Updated language translations should be pulled from [Transifex](https://app.transifex.com/netbox-community/netbox/dashboard/) and re-compiled for each new release. First, retrieve any updated translation files using the Transifex CLI client: + +```no-highlight +tx pull +``` + +Then, compile these portable (`.po`) files for use in the application: + +```no-highlight +./manage.py compilemessages +``` + +!!! tip + Consult the translation documentation for more detail on [updating translated strings](./translations.md#updating-translated-strings) if you've not set up the Transifex client already. ### Update Version and Changelog diff --git a/docs/development/translations.md b/docs/development/translations.md index eca9ce71f..43733c6d1 100644 --- a/docs/development/translations.md +++ b/docs/development/translations.md @@ -16,26 +16,31 @@ To update the English `.po` file from which all translations are derived, use th Then, commit the change and push to the `develop` branch on GitHub. Any new strings will appear for translation on Transifex automatically. +!!! note + It is typically not necessary to update source strings manually, as this is done nightly by a [GitHub action](https://github.com/netbox-community/netbox/blob/develop/.github/workflows/update-translation-strings.yml). + ## Updating Translated Strings Typically, translated strings need to be updated only as part of the NetBox [release process](./release-checklist.md). Check the Transifex dashboard for languages that are not marked _ready for use_, being sure to click _Show all languages_ if it appears at the bottom of the list. Use machine translation to round out any not-ready languages. It's not necessary to review the machine translation immediately as the translation teams will handle that aspect; the goal at this stage is to get translations included in the Transifex pull request. -To update translated strings, start by initiating a sync from Transifex. From the Transifex dashboard, navigate to Settings > Integrations > GitHub > Manage, and click the **Manual Sync** button at top right. +To download translated strings automatically, you'll need to: -![Transifex manual sync](../media/development/transifex_sync.png) +1. Install the [Transifex CLI client](https://github.com/transifex/cli) +2. Generate a [Transifex API token](https://app.transifex.com/user/settings/api/) -Enter a threshold percentage of 1 (to ensure all translations are captured) and select the `develop` branch, then click **Sync**. This will initiate a pull request to GitHub to update any newly modified translation (`.po`) files. +Once you have the client set up, run the following command: -!!! tip - The new PR should appear within a few minutes. If it does not, check that there are in fact new translations to be added. +```no-highlight +TX_TOKEN=$TOKEN tx pull +``` -![Transifex pull request](../media/development/transifex_pull_request.png) +This will download all portable (`.po`) translation files from Transifex, updating them locally as needed. -Once the PR has been merged, the updated strings need to be compiled into new `.mo` files so they can be used by the application. Update the `develop` branch locally to pull in the changes from the Transifex PR, then run Django's [`compilemessages`](https://docs.djangoproject.com/en/stable/ref/django-admin/#django-admin-compilemessages) management command: +Once retrieved, the updated strings need to be compiled into new `.mo` files so they can be used by the application. Run Django's [`compilemessages`](https://docs.djangoproject.com/en/stable/ref/django-admin/#django-admin-compilemessages) management command to compile them: -```nohighlight +```no-highlight ./manage.py compilemessages ``` diff --git a/docs/media/development/transifex_pull_request.png b/docs/media/development/transifex_pull_request.png deleted file mode 100644 index e3ae76991..000000000 Binary files a/docs/media/development/transifex_pull_request.png and /dev/null differ diff --git a/docs/media/development/transifex_sync.png b/docs/media/development/transifex_sync.png deleted file mode 100644 index 44022cc4d..000000000 Binary files a/docs/media/development/transifex_sync.png and /dev/null differ diff --git a/docs/models/circuits/virtualcircuit.md b/docs/models/circuits/virtualcircuit.md new file mode 100644 index 000000000..a379b6330 --- /dev/null +++ b/docs/models/circuits/virtualcircuit.md @@ -0,0 +1,33 @@ +# Virtual Circuits + +A virtual circuit can connect two or more interfaces atop a set of decoupled physical connections. For example, it's very common to form a virtual connection between two virtual interfaces, each of which is bound to a physical interface on its respective device and physically connected to a [provider network](./providernetwork.md) via an independent [physical circuit](./circuit.md). + +## Fields + +### Provider Network + +The [provider network](./providernetwork.md) across which the virtual circuit is formed. + +### Provider Account + +The [provider account](./provideraccount.md) with which the virtual circuit is associated (if any). + +### Circuit ID + +The unique identifier assigned to the virtual circuit by its [provider](./provider.md). + +### Status + +The operational status of the virtual circuit. By default, the following statuses are available: + +| Name | +|----------------| +| Planned | +| Provisioning | +| Active | +| Offline | +| Deprovisioning | +| Decommissioned | + +!!! tip "Custom circuit statuses" + Additional circuit statuses may be defined by setting `Circuit.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. diff --git a/docs/models/circuits/virtualcircuittermination.md b/docs/models/circuits/virtualcircuittermination.md new file mode 100644 index 000000000..82ea43eef --- /dev/null +++ b/docs/models/circuits/virtualcircuittermination.md @@ -0,0 +1,21 @@ +# Virtual Circuit Terminations + +This model represents the connection of a virtual [interface](../dcim/interface.md) to a [virtual circuit](./virtualcircuit.md). + +## Fields + +### Virtual Circuit + +The [virtual circuit](./virtualcircuit.md) to which the interface is connected. + +### Interface + +The [interface](../dcim/interface.md) connected to the virtual circuit. + +### Role + +The functional role of the termination. This depends on the virtual circuit's topology, which is typically either peer-to-peer or hub-and-spoke (multipoint). Valid choices include: + +* Peer +* Hub +* Spoke diff --git a/docs/models/dcim/interface.md b/docs/models/dcim/interface.md index fb7198682..f2af1a2ad 100644 --- a/docs/models/dcim/interface.md +++ b/docs/models/dcim/interface.md @@ -45,9 +45,12 @@ The operation duplex (full, half, or auto). The [virtual routing and forwarding](../ipam/vrf.md) instance to which this interface is assigned. -### MAC Address +### Primary MAC Address -The 48-bit MAC address (for Ethernet interfaces). +The [MAC address](./macaddress.md) assigned to this interface which is designated as its primary. + +!!! note "Changed in NetBox v4.2" + The MAC address of an interface (formerly a concrete database field) is available as a property, `mac_address`, which reflects the value of the primary linked [MAC address](./macaddress.md) object. ### WWN diff --git a/docs/models/dcim/macaddress.md b/docs/models/dcim/macaddress.md new file mode 100644 index 000000000..fe3d1f0e3 --- /dev/null +++ b/docs/models/dcim/macaddress.md @@ -0,0 +1,11 @@ +# MAC Addresses + +A MAC address object in NetBox comprises a single Ethernet link layer address, and represents a MAC address as reported by or assigned to a network interface. MAC addresses can be assigned to [device](../dcim/device.md) and [virtual machine](../virtualization/virtualmachine.md) interfaces. A MAC address can be specified as the primary MAC address for a given device or VM interface. + +Most interfaces have only a single MAC address, hard-coded at the factory. However, on some devices (particularly virtual interfaces) it is possible to assign additional MAC addresses or change existing ones. For this reason NetBox allows multiple MACAddress objects to be assigned to a single interface. + +## Fields + +### MAC Address + +The 48-bit MAC address, in colon-hexadecimal notation (e.g. `aa:bb:cc:11:22:33`). diff --git a/docs/models/virtualization/vminterface.md b/docs/models/virtualization/vminterface.md index 4a0c474f9..6617b5e59 100644 --- a/docs/models/virtualization/vminterface.md +++ b/docs/models/virtualization/vminterface.md @@ -27,9 +27,12 @@ An interface on the same VM with which this interface is bridged. If not selected, this interface will be treated as disabled/inoperative. -### MAC Address +### Primary MAC Address -The 48-bit MAC address (for Ethernet interfaces). +The [MAC address](./macaddress.md) assigned to this interface which is designated as its primary. + +!!! note "Changed in NetBox v4.2" + The MAC address of an interface (formerly a concrete database field) is available as a property, `mac_address`, which reflects the value of the primary linked [MAC address](./macaddress.md) object. ### MTU diff --git a/docs/models/vpn/ikepolicy.md b/docs/models/vpn/ikepolicy.md index d2da28d16..b78b0fe50 100644 --- a/docs/models/vpn/ikepolicy.md +++ b/docs/models/vpn/ikepolicy.md @@ -1,6 +1,6 @@ # IKE Policies -An [Internet Key Exhcnage (IKE)](https://en.wikipedia.org/wiki/Internet_Key_Exchange) policy defines an IKE version, mode, and set of [proposals](./ikeproposal.md) to be used in IKE negotiation. These policies are referenced by [IPSec profiles](./ipsecprofile.md). +An [Internet Key Exchange (IKE)](https://en.wikipedia.org/wiki/Internet_Key_Exchange) policy defines an IKE version, mode, and set of [proposals](./ikeproposal.md) to be used in IKE negotiation. These policies are referenced by [IPSec profiles](./ipsecprofile.md). ## Fields diff --git a/docs/plugins/development/views.md b/docs/plugins/development/views.md index 1f5f164fd..3b6213917 100644 --- a/docs/plugins/development/views.md +++ b/docs/plugins/development/views.md @@ -185,6 +185,9 @@ class MyView(generic.ObjectView): ) ``` +!!! note "Changed in NetBox v4.2" + The `register_model_view()` function was extended in NetBox v4.2 to support registration of list views by passing `detail=False`. + ::: utilities.views.register_model_view ::: utilities.views.ViewTab diff --git a/docs/release-notes/version-4.1.md b/docs/release-notes/version-4.1.md index 741425ac1..397741171 100644 --- a/docs/release-notes/version-4.1.md +++ b/docs/release-notes/version-4.1.md @@ -1,5 +1,37 @@ # NetBox v4.1 +## v4.1.7 (FUTURE) + +### Enhancements + +* [#15239](https://github.com/netbox-community/netbox/issues/15239) - Enable adding/removing individual VLANs while bulk editing device interfaces +* [#17871](https://github.com/netbox-community/netbox/issues/17871) - Enable the assignment/removal of virtualization cluster via device bulk edit +* [#17934](https://github.com/netbox-community/netbox/issues/17934) - Add 1000Base-LX interface type +* [#18007](https://github.com/netbox-community/netbox/issues/18007) - Hide sensitive parameters under data source view (even for privileged users) + +### Bug Fixes + +* [#17459](https://github.com/netbox-community/netbox/issues/17459) - Correct help text on `name` field of module type component templates +* [#17901](https://github.com/netbox-community/netbox/issues/17901) - Ensure GraphiQL UI resources are served locally +* [#17921](https://github.com/netbox-community/netbox/issues/17921) - Fix scheduling of recurring custom scripts +* [#17923](https://github.com/netbox-community/netbox/issues/17923) - Fix the execution of custom scripts via REST API & management command +* [#17963](https://github.com/netbox-community/netbox/issues/17963) - Fix selection of all listed objects during bulk edit +* [#17969](https://github.com/netbox-community/netbox/issues/17969) - Fix system info export when a config revision exists +* [#17972](https://github.com/netbox-community/netbox/issues/17972) - Force evaluation of `LOGIN_REQUIRED` when requesting static media +* [#17986](https://github.com/netbox-community/netbox/issues/17986) - Correct labels for virtual machine & virtual disk size properties +* [#18037](https://github.com/netbox-community/netbox/issues/18037) - Fix validation of maximum VLAN ID value when defining VLAN groups +* [#18038](https://github.com/netbox-community/netbox/issues/18038) - The `to_grams()` utility function should always return an integer value + +--- + +## v4.1.6 (2024-10-31) + +### Bug Fixes + +* [#17700](https://github.com/netbox-community/netbox/issues/17700) - Fix warning when no scripts are found within a script module +* [#17884](https://github.com/netbox-community/netbox/issues/17884) - Fix translation support for certain tab headings +* [#17885](https://github.com/netbox-community/netbox/issues/17885) - Fix regression preventing custom scripts from executing + ## v4.1.5 (2024-10-28) ### Enhancements diff --git a/mkdocs.yml b/mkdocs.yml index 00e03a4ce..a66baa286 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -174,6 +174,8 @@ nav: - Provider: 'models/circuits/provider.md' - Provider Account: 'models/circuits/provideraccount.md' - Provider Network: 'models/circuits/providernetwork.md' + - Virtual Circuit: 'models/circuits/virtualcircuit.md' + - Virtual Circuit Termination: 'models/circuits/virtualcircuittermination.md' - Core: - DataFile: 'models/core/datafile.md' - DataSource: 'models/core/datasource.md' diff --git a/netbox/circuits/api/serializers_/circuits.py b/netbox/circuits/api/serializers_/circuits.py index 96a686a65..70644a7b7 100644 --- a/netbox/circuits/api/serializers_/circuits.py +++ b/netbox/circuits/api/serializers_/circuits.py @@ -2,9 +2,13 @@ from django.contrib.contenttypes.models import ContentType from drf_spectacular.utils import extend_schema_field from rest_framework import serializers -from circuits.choices import CircuitPriorityChoices, CircuitStatusChoices +from circuits.choices import CircuitPriorityChoices, CircuitStatusChoices, VirtualCircuitTerminationRoleChoices from circuits.constants import CIRCUIT_TERMINATION_TERMINATION_TYPES -from circuits.models import Circuit, CircuitGroup, CircuitGroupAssignment, CircuitTermination, CircuitType +from circuits.models import ( + Circuit, CircuitGroup, CircuitGroupAssignment, CircuitTermination, CircuitType, VirtualCircuit, + VirtualCircuitTermination, +) +from dcim.api.serializers_.device_components import InterfaceSerializer from dcim.api.serializers_.cables import CabledObjectSerializer from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer @@ -20,6 +24,8 @@ __all__ = ( 'CircuitGroupSerializer', 'CircuitTerminationSerializer', 'CircuitTypeSerializer', + 'VirtualCircuitSerializer', + 'VirtualCircuitTerminationSerializer', ) @@ -53,8 +59,8 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer): class Meta: model = CircuitTermination fields = [ - 'id', 'url', 'display_url', 'display', 'termination_type', 'termination_id', 'termination', 'provider_network', 'port_speed', 'upstream_speed', - 'xconnect_id', 'description', + 'id', 'url', 'display_url', 'display', 'termination_type', 'termination_id', 'termination', + 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', ] @extend_schema_field(serializers.JSONField(allow_null=True)) @@ -132,9 +138,10 @@ class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer class Meta: model = CircuitTermination fields = [ - 'id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'termination_type', 'termination_id', 'termination', 'provider_network', 'port_speed', - 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_end', - 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', + 'id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'termination_type', 'termination_id', + 'termination', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', + 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', + 'last_updated', '_occupied', ] brief_fields = ('id', 'url', 'display', 'circuit', 'term_side', 'description', 'cable', '_occupied') @@ -156,3 +163,32 @@ class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_): 'id', 'url', 'display_url', 'display', 'group', 'circuit', 'priority', 'tags', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'group', 'circuit', 'priority') + + +class VirtualCircuitSerializer(NetBoxModelSerializer): + provider_network = ProviderNetworkSerializer(nested=True) + provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None) + status = ChoiceField(choices=CircuitStatusChoices, required=False) + tenant = TenantSerializer(nested=True, required=False, allow_null=True) + + class Meta: + model = VirtualCircuit + fields = [ + 'id', 'url', 'display_url', 'display', 'cid', 'provider_network', 'provider_account', 'status', 'tenant', + 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', + ] + brief_fields = ('id', 'url', 'display', 'provider_network', 'cid', 'description') + + +class VirtualCircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer): + virtual_circuit = VirtualCircuitSerializer(nested=True) + role = ChoiceField(choices=VirtualCircuitTerminationRoleChoices, required=False) + interface = InterfaceSerializer(nested=True) + + class Meta: + model = VirtualCircuitTermination + fields = [ + 'id', 'url', 'display_url', 'display', 'virtual_circuit', 'role', 'interface', 'description', 'tags', + 'custom_fields', 'created', 'last_updated', + ] + brief_fields = ('id', 'url', 'display', 'virtual_circuit', 'role', 'interface', 'description') diff --git a/netbox/circuits/api/urls.py b/netbox/circuits/api/urls.py index 00af3dec6..6f257f694 100644 --- a/netbox/circuits/api/urls.py +++ b/netbox/circuits/api/urls.py @@ -17,5 +17,9 @@ router.register('circuit-terminations', views.CircuitTerminationViewSet) router.register('circuit-groups', views.CircuitGroupViewSet) router.register('circuit-group-assignments', views.CircuitGroupAssignmentViewSet) +# Virtual circuits +router.register('virtual-circuits', views.VirtualCircuitViewSet) +router.register('virtual-circuit-terminations', views.VirtualCircuitTerminationViewSet) + app_name = 'circuits-api' urlpatterns = router.urls diff --git a/netbox/circuits/api/views.py b/netbox/circuits/api/views.py index 8cce013d7..3b49075be 100644 --- a/netbox/circuits/api/views.py +++ b/netbox/circuits/api/views.py @@ -93,3 +93,23 @@ class ProviderNetworkViewSet(NetBoxModelViewSet): queryset = ProviderNetwork.objects.all() serializer_class = serializers.ProviderNetworkSerializer filterset_class = filtersets.ProviderNetworkFilterSet + + +# +# Virtual circuits +# + +class VirtualCircuitViewSet(NetBoxModelViewSet): + queryset = VirtualCircuit.objects.all() + serializer_class = serializers.VirtualCircuitSerializer + filterset_class = filtersets.VirtualCircuitFilterSet + + +# +# Virtual circuit terminations +# + +class VirtualCircuitTerminationViewSet(PassThroughPortMixin, NetBoxModelViewSet): + queryset = VirtualCircuitTermination.objects.all() + serializer_class = serializers.VirtualCircuitTerminationSerializer + filterset_class = filtersets.VirtualCircuitTerminationFilterSet diff --git a/netbox/circuits/choices.py b/netbox/circuits/choices.py index 8c25c7459..4d6132d7a 100644 --- a/netbox/circuits/choices.py +++ b/netbox/circuits/choices.py @@ -92,3 +92,19 @@ class CircuitPriorityChoices(ChoiceSet): (PRIORITY_TERTIARY, _('Tertiary')), (PRIORITY_INACTIVE, _('Inactive')), ] + + +# +# Virtual circuits +# + +class VirtualCircuitTerminationRoleChoices(ChoiceSet): + ROLE_PEER = 'peer' + ROLE_HUB = 'hub' + ROLE_SPOKE = 'spoke' + + CHOICES = [ + (ROLE_PEER, _('Peer'), 'green'), + (ROLE_HUB, _('Hub'), 'blue'), + (ROLE_SPOKE, _('Spoke'), 'orange'), + ] diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index 4a2a972f3..825df9558 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -3,7 +3,7 @@ from django.db.models import Q from django.utils.translation import gettext as _ from dcim.filtersets import CabledObjectFilterSet -from dcim.models import Location, Region, Site, SiteGroup +from dcim.models import Interface, Location, Region, Site, SiteGroup from ipam.models import ASN from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet @@ -20,6 +20,8 @@ __all__ = ( 'ProviderNetworkFilterSet', 'ProviderAccountFilterSet', 'ProviderFilterSet', + 'VirtualCircuitFilterSet', + 'VirtualCircuitTerminationFilterSet', ) @@ -239,7 +241,9 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte class Meta: model = Circuit - fields = ('id', 'cid', 'description', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit') + fields = ( + 'id', 'cid', 'description', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit', + ) def search(self, queryset, name, value): if not value.strip(): @@ -334,8 +338,8 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): class Meta: model = CircuitTermination fields = ( - 'id', 'termination_id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', 'mark_connected', - 'pp_info', 'cable_end', + 'id', 'termination_id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', + 'mark_connected', 'pp_info', 'cable_end', ) def search(self, queryset, name, value): @@ -404,3 +408,108 @@ class CircuitGroupAssignmentFilterSet(NetBoxModelFilterSet): Q(circuit__cid__icontains=value) | Q(group__name__icontains=value) ) + + +class VirtualCircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet): + provider_id = django_filters.ModelMultipleChoiceFilter( + field_name='provider_network__provider', + queryset=Provider.objects.all(), + label=_('Provider (ID)'), + ) + provider = django_filters.ModelMultipleChoiceFilter( + field_name='provider_network__provider__slug', + queryset=Provider.objects.all(), + to_field_name='slug', + label=_('Provider (slug)'), + ) + provider_account_id = django_filters.ModelMultipleChoiceFilter( + field_name='provider_account', + queryset=ProviderAccount.objects.all(), + label=_('Provider account (ID)'), + ) + provider_account = django_filters.ModelMultipleChoiceFilter( + field_name='provider_account__account', + queryset=Provider.objects.all(), + to_field_name='account', + label=_('Provider account (account)'), + ) + provider_network_id = django_filters.ModelMultipleChoiceFilter( + queryset=ProviderNetwork.objects.all(), + label=_('Provider network (ID)'), + ) + status = django_filters.MultipleChoiceFilter( + choices=CircuitStatusChoices, + null_value=None + ) + + class Meta: + model = VirtualCircuit + fields = ('id', 'cid', 'description') + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(cid__icontains=value) | + Q(description__icontains=value) | + Q(comments__icontains=value) + ).distinct() + + +class VirtualCircuitTerminationFilterSet(NetBoxModelFilterSet): + q = django_filters.CharFilter( + method='search', + label=_('Search'), + ) + virtual_circuit_id = django_filters.ModelMultipleChoiceFilter( + queryset=VirtualCircuit.objects.all(), + label=_('Virtual circuit'), + ) + role = django_filters.MultipleChoiceFilter( + choices=VirtualCircuitTerminationRoleChoices, + null_value=None + ) + provider_id = django_filters.ModelMultipleChoiceFilter( + field_name='virtual_circuit__provider_network__provider', + queryset=Provider.objects.all(), + label=_('Provider (ID)'), + ) + provider = django_filters.ModelMultipleChoiceFilter( + field_name='virtual_circuit__provider_network__provider__slug', + queryset=Provider.objects.all(), + to_field_name='slug', + label=_('Provider (slug)'), + ) + provider_account_id = django_filters.ModelMultipleChoiceFilter( + field_name='virtual_circuit__provider_account', + queryset=ProviderAccount.objects.all(), + label=_('Provider account (ID)'), + ) + provider_account = django_filters.ModelMultipleChoiceFilter( + field_name='virtual_circuit__provider_account__account', + queryset=ProviderAccount.objects.all(), + to_field_name='account', + label=_('Provider account (account)'), + ) + provider_network_id = django_filters.ModelMultipleChoiceFilter( + queryset=ProviderNetwork.objects.all(), + field_name='virtual_circuit__provider_network', + label=_('Provider network (ID)'), + ) + interface_id = django_filters.ModelMultipleChoiceFilter( + queryset=Interface.objects.all(), + field_name='interface', + label=_('Interface (ID)'), + ) + + class Meta: + model = VirtualCircuitTermination + fields = ('id', 'interface_id', 'description') + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(virtual_circuit__cid__icontains=value) | + Q(description__icontains=value) + ).distinct() diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py index e3f0b5d0c..021635a1a 100644 --- a/netbox/circuits/forms/bulk_edit.py +++ b/netbox/circuits/forms/bulk_edit.py @@ -3,7 +3,9 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import gettext_lazy as _ -from circuits.choices import CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices +from circuits.choices import ( + CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices, VirtualCircuitTerminationRoleChoices, +) from circuits.constants import CIRCUIT_TERMINATION_TERMINATION_TYPES from circuits.models import * from dcim.models import Site @@ -28,6 +30,8 @@ __all__ = ( 'ProviderBulkEditForm', 'ProviderAccountBulkEditForm', 'ProviderNetworkBulkEditForm', + 'VirtualCircuitBulkEditForm', + 'VirtualCircuitTerminationBulkEditForm', ) @@ -291,3 +295,62 @@ class CircuitGroupAssignmentBulkEditForm(NetBoxModelBulkEditForm): FieldSet('circuit', 'priority'), ) nullable_fields = ('priority',) + + +class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm): + provider_network = DynamicModelChoiceField( + label=_('Provider network'), + queryset=ProviderNetwork.objects.all(), + required=False + ) + provider_account = DynamicModelChoiceField( + label=_('Provider account'), + queryset=ProviderAccount.objects.all(), + required=False + ) + status = forms.ChoiceField( + label=_('Status'), + choices=add_blank_choice(CircuitStatusChoices), + required=False, + initial='' + ) + tenant = DynamicModelChoiceField( + label=_('Tenant'), + queryset=Tenant.objects.all(), + required=False + ) + description = forms.CharField( + label=_('Description'), + max_length=100, + required=False + ) + comments = CommentField() + + model = VirtualCircuit + fieldsets = ( + FieldSet('provider_network', 'provider_account', 'status', 'description', name=_('Virtual circuit')), + FieldSet('tenant', name=_('Tenancy')), + ) + nullable_fields = ( + 'provider_account', 'tenant', 'description', 'comments', + ) + + +class VirtualCircuitTerminationBulkEditForm(NetBoxModelBulkEditForm): + role = forms.ChoiceField( + label=_('Role'), + choices=add_blank_choice(VirtualCircuitTerminationRoleChoices), + required=False, + initial='' + ) + description = forms.CharField( + label=_('Description'), + max_length=200, + required=False + ) + + model = VirtualCircuitTermination + fieldsets = ( + FieldSet('role', 'description'), + ) + nullable_fields = ('description',) diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index eab87b1f5..7f5ffde6e 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _ from circuits.choices import * from circuits.constants import * from circuits.models import * +from dcim.models import Interface from netbox.choices import DistanceUnitChoices from netbox.forms import NetBoxModelImportForm from tenancy.models import Tenant @@ -20,6 +21,9 @@ __all__ = ( 'ProviderImportForm', 'ProviderAccountImportForm', 'ProviderNetworkImportForm', + 'VirtualCircuitImportForm', + 'VirtualCircuitTerminationImportForm', + 'VirtualCircuitTerminationImportRelatedForm', ) @@ -179,3 +183,73 @@ class CircuitGroupAssignmentImportForm(NetBoxModelImportForm): class Meta: model = CircuitGroupAssignment fields = ('circuit', 'group', 'priority') + + +class VirtualCircuitImportForm(NetBoxModelImportForm): + provider_network = CSVModelChoiceField( + label=_('Provider network'), + queryset=ProviderNetwork.objects.all(), + to_field_name='name', + help_text=_('The network to which this virtual circuit belongs') + ) + provider_account = CSVModelChoiceField( + label=_('Provider account'), + queryset=ProviderAccount.objects.all(), + to_field_name='account', + help_text=_('Assigned provider account (if any)'), + required=False + ) + status = CSVChoiceField( + label=_('Status'), + choices=CircuitStatusChoices, + help_text=_('Operational status') + ) + tenant = CSVModelChoiceField( + label=_('Tenant'), + queryset=Tenant.objects.all(), + required=False, + to_field_name='name', + help_text=_('Assigned tenant') + ) + + class Meta: + model = VirtualCircuit + fields = [ + 'cid', 'provider_network', 'provider_account', 'status', 'tenant', 'description', 'comments', 'tags', + ] + + +class BaseVirtualCircuitTerminationImportForm(forms.ModelForm): + virtual_circuit = CSVModelChoiceField( + label=_('Virtual circuit'), + queryset=VirtualCircuit.objects.all(), + to_field_name='cid', + ) + role = CSVChoiceField( + label=_('Role'), + choices=VirtualCircuitTerminationRoleChoices, + help_text=_('Operational role') + ) + interface = CSVModelChoiceField( + label=_('Interface'), + queryset=Interface.objects.all(), + to_field_name='pk', + ) + + +class VirtualCircuitTerminationImportRelatedForm(BaseVirtualCircuitTerminationImportForm): + + class Meta: + model = VirtualCircuitTermination + fields = [ + 'virtual_circuit', 'role', 'interface', 'description', + ] + + +class VirtualCircuitTerminationImportForm(NetBoxModelImportForm, BaseVirtualCircuitTerminationImportForm): + + class Meta: + model = VirtualCircuitTermination + fields = [ + 'virtual_circuit', 'role', 'interface', 'description', 'tags', + ] diff --git a/netbox/circuits/forms/filtersets.py b/netbox/circuits/forms/filtersets.py index b585ce079..47ce24d97 100644 --- a/netbox/circuits/forms/filtersets.py +++ b/netbox/circuits/forms/filtersets.py @@ -1,7 +1,10 @@ from django import forms from django.utils.translation import gettext as _ -from circuits.choices import CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices, CircuitTerminationSideChoices +from circuits.choices import ( + CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices, CircuitTerminationSideChoices, + VirtualCircuitTerminationRoleChoices, +) from circuits.models import * from dcim.models import Location, Region, Site, SiteGroup from ipam.models import ASN @@ -22,6 +25,8 @@ __all__ = ( 'ProviderFilterForm', 'ProviderAccountFilterForm', 'ProviderNetworkFilterForm', + 'VirtualCircuitFilterForm', + 'VirtualCircuitTerminationFilterForm', ) @@ -116,7 +121,10 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi fieldsets = ( FieldSet('q', 'filter_id', 'tag'), FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), - FieldSet('type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit', name=_('Attributes')), + FieldSet( + 'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit', + name=_('Attributes') + ), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), @@ -292,3 +300,74 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm): required=False ) tag = TagFilterField(model) + + +class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm): + model = VirtualCircuit + fieldsets = ( + FieldSet('q', 'filter_id', 'tag'), + FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), + FieldSet('status', name=_('Attributes')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + ) + selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id') + provider_id = DynamicModelMultipleChoiceField( + queryset=Provider.objects.all(), + required=False, + label=_('Provider') + ) + provider_account_id = DynamicModelMultipleChoiceField( + queryset=ProviderAccount.objects.all(), + required=False, + query_params={ + 'provider_id': '$provider_id' + }, + label=_('Provider account') + ) + provider_network_id = DynamicModelMultipleChoiceField( + queryset=ProviderNetwork.objects.all(), + required=False, + query_params={ + 'provider_id': '$provider_id' + }, + label=_('Provider network') + ) + status = forms.MultipleChoiceField( + label=_('Status'), + choices=CircuitStatusChoices, + required=False + ) + tag = TagFilterField(model) + + +class VirtualCircuitTerminationFilterForm(NetBoxModelFilterSetForm): + model = VirtualCircuitTermination + fieldsets = ( + FieldSet('q', 'filter_id', 'tag'), + FieldSet('virtual_circuit_id', 'role', name=_('Virtual circuit')), + FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), + ) + virtual_circuit_id = DynamicModelMultipleChoiceField( + queryset=VirtualCircuit.objects.all(), + required=False, + label=_('Virtual circuit') + ) + role = forms.MultipleChoiceField( + label=_('Role'), + choices=VirtualCircuitTerminationRoleChoices, + required=False + ) + provider_network_id = DynamicModelMultipleChoiceField( + queryset=ProviderNetwork.objects.all(), + required=False, + query_params={ + 'provider_id': '$provider_id' + }, + label=_('Provider network') + ) + provider_id = DynamicModelMultipleChoiceField( + queryset=Provider.objects.all(), + required=False, + label=_('Provider') + ) + tag = TagFilterField(model) diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index 10cd06563..e43c37525 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -1,16 +1,21 @@ +from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import gettext_lazy as _ -from circuits.choices import CircuitCommitRateChoices, CircuitTerminationPortSpeedChoices +from circuits.choices import ( + CircuitCommitRateChoices, CircuitTerminationPortSpeedChoices, VirtualCircuitTerminationRoleChoices, +) from circuits.constants import * from circuits.models import * -from dcim.models import Site +from dcim.models import Interface, Site from ipam.models import ASN from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm from utilities.forms import get_field_value -from utilities.forms.fields import CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField +from utilities.forms.fields import ( + CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, +) from utilities.forms.rendering import FieldSet, InlineFields from utilities.forms.widgets import DatePicker, HTMXSelect, NumberWithOptions from utilities.templatetags.builtins.filters import bettertitle @@ -24,6 +29,8 @@ __all__ = ( 'ProviderForm', 'ProviderAccountForm', 'ProviderNetworkForm', + 'VirtualCircuitForm', + 'VirtualCircuitTerminationForm', ) @@ -50,7 +57,9 @@ class ProviderForm(NetBoxModelForm): class ProviderAccountForm(NetBoxModelForm): provider = DynamicModelChoiceField( label=_('Provider'), - queryset=Provider.objects.all() + queryset=Provider.objects.all(), + selector=True, + quick_add=True ) comments = CommentField() @@ -64,7 +73,9 @@ class ProviderAccountForm(NetBoxModelForm): class ProviderNetworkForm(NetBoxModelForm): provider = DynamicModelChoiceField( label=_('Provider'), - queryset=Provider.objects.all() + queryset=Provider.objects.all(), + selector=True, + quick_add=True ) comments = CommentField() @@ -97,7 +108,8 @@ class CircuitForm(TenancyForm, NetBoxModelForm): provider = DynamicModelChoiceField( label=_('Provider'), queryset=Provider.objects.all(), - selector=True + selector=True, + quick_add=True ) provider_account = DynamicModelChoiceField( label=_('Provider account'), @@ -108,7 +120,8 @@ class CircuitForm(TenancyForm, NetBoxModelForm): } ) type = DynamicModelChoiceField( - queryset=CircuitType.objects.all() + queryset=CircuitType.objects.all(), + quick_add=True ) comments = CommentField() @@ -249,3 +262,66 @@ class CircuitGroupAssignmentForm(NetBoxModelForm): fields = [ 'group', 'circuit', 'priority', 'tags', ] + + +class VirtualCircuitForm(TenancyForm, NetBoxModelForm): + provider_network = DynamicModelChoiceField( + label=_('Provider network'), + queryset=ProviderNetwork.objects.all(), + selector=True + ) + provider_account = DynamicModelChoiceField( + label=_('Provider account'), + queryset=ProviderAccount.objects.all(), + required=False + ) + comments = CommentField() + + fieldsets = ( + FieldSet( + 'provider_network', 'provider_account', 'cid', 'status', 'description', 'tags', name=_('Virtual circuit'), + ), + FieldSet('tenant_group', 'tenant', name=_('Tenancy')), + ) + + class Meta: + model = VirtualCircuit + fields = [ + 'cid', 'provider_network', 'provider_account', 'status', 'description', 'tenant_group', 'tenant', + 'comments', 'tags', + ] + + +class VirtualCircuitTerminationForm(NetBoxModelForm): + virtual_circuit = DynamicModelChoiceField( + label=_('Virtual circuit'), + queryset=VirtualCircuit.objects.all(), + selector=True + ) + role = forms.ChoiceField( + choices=VirtualCircuitTerminationRoleChoices, + widget=HTMXSelect(), + label=_('Role') + ) + interface = DynamicModelChoiceField( + label=_('Interface'), + queryset=Interface.objects.all(), + selector=True, + query_params={ + 'kind': 'virtual', + 'virtual_circuit_termination_id': 'null', + }, + context={ + 'parent': 'device', + } + ) + + fieldsets = ( + FieldSet('virtual_circuit', 'role', 'interface', 'description', 'tags'), + ) + + class Meta: + model = VirtualCircuitTermination + fields = [ + 'virtual_circuit', 'role', 'interface', 'description', 'tags', + ] diff --git a/netbox/circuits/graphql/filters.py b/netbox/circuits/graphql/filters.py index b8398b2b9..36ddc25b2 100644 --- a/netbox/circuits/graphql/filters.py +++ b/netbox/circuits/graphql/filters.py @@ -4,14 +4,16 @@ from circuits import filtersets, models from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin __all__ = ( - 'CircuitTerminationFilter', 'CircuitFilter', 'CircuitGroupAssignmentFilter', 'CircuitGroupFilter', + 'CircuitTerminationFilter', 'CircuitTypeFilter', 'ProviderFilter', 'ProviderAccountFilter', 'ProviderNetworkFilter', + 'VirtualCircuitFilter', + 'VirtualCircuitTerminationFilter', ) @@ -61,3 +63,15 @@ class ProviderAccountFilter(BaseFilterMixin): @autotype_decorator(filtersets.ProviderNetworkFilterSet) class ProviderNetworkFilter(BaseFilterMixin): pass + + +@strawberry_django.filter(models.VirtualCircuit, lookups=True) +@autotype_decorator(filtersets.VirtualCircuitFilterSet) +class VirtualCircuitFilter(BaseFilterMixin): + pass + + +@strawberry_django.filter(models.VirtualCircuitTermination, lookups=True) +@autotype_decorator(filtersets.VirtualCircuitTerminationFilterSet) +class VirtualCircuitTerminationFilter(BaseFilterMixin): + pass diff --git a/netbox/circuits/graphql/schema.py b/netbox/circuits/graphql/schema.py index ac23421ce..9c683ce45 100644 --- a/netbox/circuits/graphql/schema.py +++ b/netbox/circuits/graphql/schema.py @@ -31,3 +31,9 @@ class CircuitsQuery: provider_network: ProviderNetworkType = strawberry_django.field() provider_network_list: List[ProviderNetworkType] = strawberry_django.field() + + virtual_circuit: VirtualCircuitType = strawberry_django.field() + virtual_circuit_list: List[VirtualCircuitType] = strawberry_django.field() + + virtual_circuit_termination: VirtualCircuitTerminationType = strawberry_django.field() + virtual_circuit_termination_list: List[VirtualCircuitTerminationType] = strawberry_django.field() diff --git a/netbox/circuits/graphql/types.py b/netbox/circuits/graphql/types.py index b52f9d18d..f2703b207 100644 --- a/netbox/circuits/graphql/types.py +++ b/netbox/circuits/graphql/types.py @@ -19,6 +19,8 @@ __all__ = ( 'ProviderType', 'ProviderAccountType', 'ProviderNetworkType', + 'VirtualCircuitTerminationType', + 'VirtualCircuitType', ) @@ -120,3 +122,32 @@ class CircuitGroupType(OrganizationalObjectType): class CircuitGroupAssignmentType(TagsMixin, BaseObjectType): group: Annotated["CircuitGroupType", strawberry.lazy('circuits.graphql.types')] circuit: Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')] + + +@strawberry_django.type( + models.VirtualCircuitTermination, + fields='__all__', + filters=VirtualCircuitTerminationFilter +) +class VirtualCircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType): + virtual_circuit: Annotated[ + "VirtualCircuitType", + strawberry.lazy('circuits.graphql.types') + ] = strawberry_django.field(select_related=["virtual_circuit"]) + interface: Annotated[ + "InterfaceType", + strawberry.lazy('dcim.graphql.types') + ] = strawberry_django.field(select_related=["interface"]) + + +@strawberry_django.type( + models.VirtualCircuit, + fields='__all__', + filters=VirtualCircuitFilter +) +class VirtualCircuitType(NetBoxObjectType): + provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"]) + provider_account: ProviderAccountType | None + tenant: TenantType | None + + terminations: List[VirtualCircuitTerminationType] diff --git a/netbox/circuits/migrations/0001_squashed.py b/netbox/circuits/migrations/0001_squashed.py index 96fa3c086..0b3d729e6 100644 --- a/netbox/circuits/migrations/0001_squashed.py +++ b/netbox/circuits/migrations/0001_squashed.py @@ -5,11 +5,9 @@ import django.db.models.deletion class Migration(migrations.Migration): - initial = True - dependencies = [ - ] + dependencies = [] replaces = [ ('circuits', '0001_initial'), @@ -98,7 +96,12 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=100)), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), - ('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='networks', to='circuits.provider')), + ( + 'provider', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='networks', to='circuits.provider' + ), + ), ], options={ 'ordering': ('provider', 'name'), diff --git a/netbox/circuits/migrations/0002_squashed_0029.py b/netbox/circuits/migrations/0002_squashed_0029.py index 11fcbd6e6..cb61d8feb 100644 --- a/netbox/circuits/migrations/0002_squashed_0029.py +++ b/netbox/circuits/migrations/0002_squashed_0029.py @@ -4,7 +4,6 @@ import taggit.managers class Migration(migrations.Migration): - dependencies = [ ('dcim', '0001_initial'), ('contenttypes', '0002_remove_content_type_name'), @@ -58,32 +57,56 @@ class Migration(migrations.Migration): migrations.AddField( model_name='circuittermination', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='circuittermination', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='circuittermination', name='circuit', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='circuits.circuit'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='circuits.circuit' + ), ), migrations.AddField( model_name='circuittermination', name='provider_network', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_terminations', to='circuits.providernetwork'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='circuit_terminations', + to='circuits.providernetwork', + ), ), migrations.AddField( model_name='circuittermination', name='site', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_terminations', to='dcim.site'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='circuit_terminations', + to='dcim.site', + ), ), migrations.AddField( model_name='circuit', name='provider', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.provider'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.provider' + ), ), migrations.AddField( model_name='circuit', @@ -93,26 +116,50 @@ class Migration(migrations.Migration): migrations.AddField( model_name='circuit', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='circuits', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='circuit', name='termination_a', - field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='circuits.circuittermination'), + field=models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='circuits.circuittermination', + ), ), migrations.AddField( model_name='circuit', name='termination_z', - field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='circuits.circuittermination'), + field=models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='circuits.circuittermination', + ), ), migrations.AddField( model_name='circuit', name='type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.circuittype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.circuittype' + ), ), migrations.AddConstraint( model_name='providernetwork', - constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_provider_name'), + constraint=models.UniqueConstraint( + fields=('provider', 'name'), name='circuits_providernetwork_provider_name' + ), ), migrations.AlterUniqueTogether( name='providernetwork', diff --git a/netbox/circuits/migrations/0003_squashed_0037.py b/netbox/circuits/migrations/0003_squashed_0037.py index 69c3e1c68..c536e422f 100644 --- a/netbox/circuits/migrations/0003_squashed_0037.py +++ b/netbox/circuits/migrations/0003_squashed_0037.py @@ -5,7 +5,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('circuits', '0003_extend_tag_support'), ('circuits', '0004_rename_cable_peer'), @@ -14,7 +13,7 @@ class Migration(migrations.Migration): ('circuits', '0034_created_datetimefield'), ('circuits', '0035_provider_asns'), ('circuits', '0036_circuit_termination_date_tags_custom_fields'), - ('circuits', '0037_new_cabling_models') + ('circuits', '0037_new_cabling_models'), ] dependencies = [ diff --git a/netbox/circuits/migrations/0038_squashed_0042.py b/netbox/circuits/migrations/0038_squashed_0042.py index f57fde3db..fa944b763 100644 --- a/netbox/circuits/migrations/0038_squashed_0042.py +++ b/netbox/circuits/migrations/0038_squashed_0042.py @@ -6,13 +6,12 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('circuits', '0038_cabling_cleanup'), ('circuits', '0039_unique_constraints'), ('circuits', '0040_provider_remove_deprecated_fields'), ('circuits', '0041_standardize_description_comments'), - ('circuits', '0042_provideraccount') + ('circuits', '0042_provideraccount'), ] dependencies = [ @@ -51,11 +50,15 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='circuittermination', - constraint=models.UniqueConstraint(fields=('circuit', 'term_side'), name='circuits_circuittermination_unique_circuit_term_side'), + constraint=models.UniqueConstraint( + fields=('circuit', 'term_side'), name='circuits_circuittermination_unique_circuit_term_side' + ), ), migrations.AddConstraint( model_name='providernetwork', - constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_unique_provider_name'), + constraint=models.UniqueConstraint( + fields=('provider', 'name'), name='circuits_providernetwork_unique_provider_name' + ), ), migrations.RemoveField( model_name='provider', @@ -84,12 +87,20 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), ('account', models.CharField(max_length=100)), ('name', models.CharField(blank=True, max_length=100)), - ('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='accounts', to='circuits.provider')), + ( + 'provider', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='accounts', to='circuits.provider' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -98,11 +109,17 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='provideraccount', - constraint=models.UniqueConstraint(condition=models.Q(('name', ''), _negated=True), fields=('provider', 'name'), name='circuits_provideraccount_unique_provider_name'), + constraint=models.UniqueConstraint( + condition=models.Q(('name', ''), _negated=True), + fields=('provider', 'name'), + name='circuits_provideraccount_unique_provider_name', + ), ), migrations.AddConstraint( model_name='provideraccount', - constraint=models.UniqueConstraint(fields=('provider', 'account'), name='circuits_provideraccount_unique_provider_account'), + constraint=models.UniqueConstraint( + fields=('provider', 'account'), name='circuits_provideraccount_unique_provider_account' + ), ), migrations.RemoveField( model_name='provider', @@ -111,7 +128,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='circuit', name='provider_account', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.provideraccount'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='circuits', + to='circuits.provideraccount', + ), preserve_default=False, ), migrations.AlterModelOptions( @@ -120,6 +143,8 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='circuit', - constraint=models.UniqueConstraint(fields=('provider_account', 'cid'), name='circuits_circuit_unique_provideraccount_cid'), + constraint=models.UniqueConstraint( + fields=('provider_account', 'cid'), name='circuits_circuit_unique_provideraccount_cid' + ), ), ] diff --git a/netbox/circuits/migrations/0044_circuit_groups.py b/netbox/circuits/migrations/0044_circuit_groups.py index 98c3b8f3d..08f6bc158 100644 --- a/netbox/circuits/migrations/0044_circuit_groups.py +++ b/netbox/circuits/migrations/0044_circuit_groups.py @@ -5,7 +5,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('circuits', '0043_circuittype_color'), ('extras', '0119_notifications'), diff --git a/netbox/circuits/migrations/0045_circuit_distance.py b/netbox/circuits/migrations/0045_circuit_distance.py index 6c970339d..9e512e7ee 100644 --- a/netbox/circuits/migrations/0045_circuit_distance.py +++ b/netbox/circuits/migrations/0045_circuit_distance.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('circuits', '0044_circuit_groups'), ] diff --git a/netbox/circuits/migrations/0046_charfield_null_choices.py b/netbox/circuits/migrations/0046_charfield_null_choices.py index 4ec21b750..2a8bcde90 100644 --- a/netbox/circuits/migrations/0046_charfield_null_choices.py +++ b/netbox/circuits/migrations/0046_charfield_null_choices.py @@ -15,7 +15,6 @@ def set_null_values(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('circuits', '0045_circuit_distance'), ] @@ -36,8 +35,5 @@ class Migration(migrations.Migration): name='cable_end', field=models.CharField(blank=True, max_length=1, null=True), ), - migrations.RunPython( - code=set_null_values, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_null_values, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/circuits/migrations/0047_circuittermination__termination.py b/netbox/circuits/migrations/0047_circuittermination__termination.py index 0cf2b424f..f78e17ec3 100644 --- a/netbox/circuits/migrations/0047_circuittermination__termination.py +++ b/netbox/circuits/migrations/0047_circuittermination__termination.py @@ -11,19 +11,17 @@ def copy_site_assignments(apps, schema_editor): Site = apps.get_model('dcim', 'Site') CircuitTermination.objects.filter(site__isnull=False).update( - termination_type=ContentType.objects.get_for_model(Site), - termination_id=models.F('site_id') + termination_type=ContentType.objects.get_for_model(Site), termination_id=models.F('site_id') ) ProviderNetwork = apps.get_model('circuits', 'ProviderNetwork') CircuitTermination.objects.filter(provider_network__isnull=False).update( termination_type=ContentType.objects.get_for_model(ProviderNetwork), - termination_id=models.F('provider_network_id') + termination_id=models.F('provider_network_id'), ) class Migration(migrations.Migration): - dependencies = [ ('circuits', '0046_charfield_null_choices'), ('contenttypes', '0002_remove_content_type_name'), @@ -41,17 +39,15 @@ class Migration(migrations.Migration): name='termination_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q(('model__in', ('region', 'sitegroup', 'site', 'location', 'providernetwork'))), + limit_choices_to=models.Q( + ('model__in', ('region', 'sitegroup', 'site', 'location', 'providernetwork')) + ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype', ), ), - # Copy over existing site assignments - migrations.RunPython( - code=copy_site_assignments, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/circuits/migrations/0048_circuitterminations_cached_relations.py b/netbox/circuits/migrations/0048_circuitterminations_cached_relations.py index 628579228..fc1cef0e5 100644 --- a/netbox/circuits/migrations/0048_circuitterminations_cached_relations.py +++ b/netbox/circuits/migrations/0048_circuitterminations_cached_relations.py @@ -20,7 +20,6 @@ def populate_denormalized_fields(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('circuits', '0047_circuittermination__termination'), ] @@ -70,13 +69,8 @@ class Migration(migrations.Migration): to='dcim.sitegroup', ), ), - # Populate denormalized FK values - migrations.RunPython( - code=populate_denormalized_fields, - reverse_code=migrations.RunPython.noop - ), - + migrations.RunPython(code=populate_denormalized_fields, reverse_code=migrations.RunPython.noop), # Delete the site ForeignKey migrations.RemoveField( model_name='circuittermination', diff --git a/netbox/circuits/migrations/0049_natural_ordering.py b/netbox/circuits/migrations/0049_natural_ordering.py index 1b4f565e8..556d6ec7c 100644 --- a/netbox/circuits/migrations/0049_natural_ordering.py +++ b/netbox/circuits/migrations/0049_natural_ordering.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('circuits', '0048_circuitterminations_cached_relations'), ('dcim', '0197_natural_sort_collation'), diff --git a/netbox/circuits/migrations/0050_virtual_circuits.py b/netbox/circuits/migrations/0050_virtual_circuits.py new file mode 100644 index 000000000..eb451b4ec --- /dev/null +++ b/netbox/circuits/migrations/0050_virtual_circuits.py @@ -0,0 +1,115 @@ +import django.db.models.deletion +import taggit.managers +from django.db import migrations, models + +import utilities.json + + +class Migration(migrations.Migration): + dependencies = [ + ('circuits', '0049_natural_ordering'), + ('dcim', '0196_qinq_svlan'), + ('extras', '0122_charfield_null_choices'), + ('tenancy', '0016_charfield_null_choices'), + ] + + operations = [ + migrations.CreateModel( + name='VirtualCircuit', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), + ('description', models.CharField(blank=True, max_length=200)), + ('comments', models.TextField(blank=True)), + ('cid', models.CharField(max_length=100)), + ('status', models.CharField(default='active', max_length=50)), + ( + 'provider_account', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='virtual_circuits', + to='circuits.provideraccount', + ), + ), + ( + 'provider_network', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name='virtual_circuits', + to='circuits.providernetwork', + ), + ), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='virtual_circuits', + to='tenancy.tenant', + ), + ), + ], + options={ + 'verbose_name': 'circuit', + 'verbose_name_plural': 'circuits', + 'ordering': ['provider_network', 'provider_account', 'cid'], + }, + ), + migrations.CreateModel( + name='VirtualCircuitTermination', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), + ('role', models.CharField(default='peer', max_length=50)), + ('description', models.CharField(blank=True, max_length=200)), + ( + 'interface', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name='virtual_circuit_termination', + to='dcim.interface', + ), + ), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ( + 'virtual_circuit', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='terminations', + to='circuits.virtualcircuit', + ), + ), + ], + options={ + 'verbose_name': 'virtual circuit termination', + 'verbose_name_plural': 'virtual circuit terminations', + 'ordering': ['virtual_circuit', 'role', 'pk'], + }, + ), + migrations.AddConstraint( + model_name='virtualcircuit', + constraint=models.UniqueConstraint( + fields=('provider_network', 'cid'), name='circuits_virtualcircuit_unique_provider_network_cid' + ), + ), + migrations.AddConstraint( + model_name='virtualcircuit', + constraint=models.UniqueConstraint( + fields=('provider_account', 'cid'), name='circuits_virtualcircuit_unique_provideraccount_cid' + ), + ), + ] diff --git a/netbox/circuits/models/__init__.py b/netbox/circuits/models/__init__.py index 7bbaf75d3..77382358b 100644 --- a/netbox/circuits/models/__init__.py +++ b/netbox/circuits/models/__init__.py @@ -1,2 +1,3 @@ from .circuits import * from .providers import * +from .virtual_circuits import * diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 85b22eaa5..5e910b5d5 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -11,7 +11,9 @@ from circuits.constants import * from dcim.models import CabledObjectModel from netbox.models import ChangeLoggedModel, OrganizationalModel, PrimaryModel from netbox.models.mixins import DistanceMixin -from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, ImageAttachmentsMixin, TagsMixin +from netbox.models.features import ( + ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, ImageAttachmentsMixin, TagsMixin, +) from utilities.fields import ColorField __all__ = ( diff --git a/netbox/circuits/models/virtual_circuits.py b/netbox/circuits/models/virtual_circuits.py new file mode 100644 index 000000000..ced68c105 --- /dev/null +++ b/netbox/circuits/models/virtual_circuits.py @@ -0,0 +1,164 @@ +from functools import cached_property + +from django.core.exceptions import ValidationError +from django.db import models +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ + +from circuits.choices import * +from netbox.models import ChangeLoggedModel, PrimaryModel +from netbox.models.features import CustomFieldsMixin, CustomLinksMixin, TagsMixin + +__all__ = ( + 'VirtualCircuit', + 'VirtualCircuitTermination', +) + + +class VirtualCircuit(PrimaryModel): + """ + A virtual connection between two or more endpoints, delivered across one or more physical circuits. + """ + cid = models.CharField( + max_length=100, + verbose_name=_('circuit ID'), + help_text=_('Unique circuit ID') + ) + provider_network = models.ForeignKey( + to='circuits.ProviderNetwork', + on_delete=models.PROTECT, + related_name='virtual_circuits' + ) + provider_account = models.ForeignKey( + to='circuits.ProviderAccount', + on_delete=models.PROTECT, + related_name='virtual_circuits', + blank=True, + null=True + ) + status = models.CharField( + verbose_name=_('status'), + max_length=50, + choices=CircuitStatusChoices, + default=CircuitStatusChoices.STATUS_ACTIVE + ) + tenant = models.ForeignKey( + to='tenancy.Tenant', + on_delete=models.PROTECT, + related_name='virtual_circuits', + blank=True, + null=True + ) + + clone_fields = ( + 'provider_network', 'provider_account', 'status', 'tenant', 'description', + ) + prerequisite_models = ( + 'circuits.ProviderNetwork', + ) + + class Meta: + ordering = ['provider_network', 'provider_account', 'cid'] + constraints = ( + models.UniqueConstraint( + fields=('provider_network', 'cid'), + name='%(app_label)s_%(class)s_unique_provider_network_cid' + ), + models.UniqueConstraint( + fields=('provider_account', 'cid'), + name='%(app_label)s_%(class)s_unique_provideraccount_cid' + ), + ) + verbose_name = _('virtual circuit') + verbose_name_plural = _('virtual circuits') + + def __str__(self): + return self.cid + + def get_status_color(self): + return CircuitStatusChoices.colors.get(self.status) + + def clean(self): + super().clean() + + if self.provider_account and self.provider_network.provider != self.provider_account.provider: + raise ValidationError({ + 'provider_account': "The assigned account must belong to the provider of the assigned network." + }) + + @property + def provider(self): + return self.provider_network.provider + + +class VirtualCircuitTermination( + CustomFieldsMixin, + CustomLinksMixin, + TagsMixin, + ChangeLoggedModel +): + virtual_circuit = models.ForeignKey( + to='circuits.VirtualCircuit', + on_delete=models.CASCADE, + related_name='terminations' + ) + role = models.CharField( + verbose_name=_('role'), + max_length=50, + choices=VirtualCircuitTerminationRoleChoices, + default=VirtualCircuitTerminationRoleChoices.ROLE_PEER + ) + interface = models.OneToOneField( + to='dcim.Interface', + on_delete=models.CASCADE, + related_name='virtual_circuit_termination' + ) + description = models.CharField( + verbose_name=_('description'), + max_length=200, + blank=True + ) + + class Meta: + ordering = ['virtual_circuit', 'role', 'pk'] + verbose_name = _('virtual circuit termination') + verbose_name_plural = _('virtual circuit terminations') + + def __str__(self): + return f'{self.virtual_circuit}: {self.get_role_display()} termination' + + def get_absolute_url(self): + return reverse('circuits:virtualcircuittermination', args=[self.pk]) + + def get_role_color(self): + return VirtualCircuitTerminationRoleChoices.colors.get(self.role) + + def to_objectchange(self, action): + objectchange = super().to_objectchange(action) + objectchange.related_object = self.virtual_circuit + return objectchange + + @property + def parent_object(self): + return self.virtual_circuit + + @cached_property + def peer_terminations(self): + if self.role == VirtualCircuitTerminationRoleChoices.ROLE_PEER: + return self.virtual_circuit.terminations.exclude(pk=self.pk).filter( + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER + ) + if self.role == VirtualCircuitTerminationRoleChoices.ROLE_HUB: + return self.virtual_circuit.terminations.filter( + role=VirtualCircuitTerminationRoleChoices.ROLE_SPOKE + ) + if self.role == VirtualCircuitTerminationRoleChoices.ROLE_SPOKE: + return self.virtual_circuit.terminations.filter( + role=VirtualCircuitTerminationRoleChoices.ROLE_HUB + ) + + def clean(self): + super().clean() + + if self.interface and not self.interface.is_virtual: + raise ValidationError("Virtual circuits may be terminated only to virtual interfaces.") diff --git a/netbox/circuits/search.py b/netbox/circuits/search.py index 7a5711f03..80725c1b8 100644 --- a/netbox/circuits/search.py +++ b/netbox/circuits/search.py @@ -80,3 +80,23 @@ class ProviderNetworkIndex(SearchIndex): ('comments', 5000), ) display_attrs = ('provider', 'service_id', 'description') + + +@register_search +class VirtualCircuitIndex(SearchIndex): + model = models.VirtualCircuit + fields = ( + ('cid', 100), + ('description', 500), + ('comments', 5000), + ) + display_attrs = ('provider', 'provider_network', 'provider_account', 'status', 'tenant', 'description') + + +@register_search +class VirtualCircuitTerminationIndex(SearchIndex): + model = models.VirtualCircuitTermination + fields = ( + ('description', 500), + ) + display_attrs = ('virtual_circuit', 'role', 'description') diff --git a/netbox/circuits/tables/__init__.py b/netbox/circuits/tables/__init__.py index b61c13cae..a436eb88d 100644 --- a/netbox/circuits/tables/__init__.py +++ b/netbox/circuits/tables/__init__.py @@ -1,3 +1,4 @@ from .circuits import * from .columns import * from .providers import * +from .virtual_circuits import * diff --git a/netbox/circuits/tables/circuits.py b/netbox/circuits/tables/circuits.py index ab9c661e6..dedb1534b 100644 --- a/netbox/circuits/tables/circuits.py +++ b/netbox/circuits/tables/circuits.py @@ -42,7 +42,8 @@ class CircuitTypeTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = CircuitType fields = ( - 'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions', + 'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated', + 'actions', ) default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug') diff --git a/netbox/circuits/tables/virtual_circuits.py b/netbox/circuits/tables/virtual_circuits.py new file mode 100644 index 000000000..b7617f297 --- /dev/null +++ b/netbox/circuits/tables/virtual_circuits.py @@ -0,0 +1,95 @@ +import django_tables2 as tables +from django.utils.translation import gettext_lazy as _ + +from circuits.models import * +from netbox.tables import NetBoxTable, columns +from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin + +__all__ = ( + 'VirtualCircuitTable', + 'VirtualCircuitTerminationTable', +) + + +class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): + cid = tables.Column( + linkify=True, + verbose_name=_('Circuit ID') + ) + provider = tables.Column( + accessor=tables.A('provider_network__provider'), + verbose_name=_('Provider'), + linkify=True + ) + provider_network = tables.Column( + linkify=True, + verbose_name=_('Provider network') + ) + provider_account = tables.Column( + linkify=True, + verbose_name=_('Account') + ) + status = columns.ChoiceFieldColumn() + termination_count = columns.LinkedCountColumn( + viewname='circuits:virtualcircuittermination_list', + url_params={'virtual_circuit_id': 'pk'}, + verbose_name=_('Terminations') + ) + comments = columns.MarkdownColumn( + verbose_name=_('Comments') + ) + tags = columns.TagColumn( + url_name='circuits:virtualcircuit_list' + ) + + class Meta(NetBoxTable.Meta): + model = VirtualCircuit + fields = ( + 'pk', 'id', 'cid', 'provider', 'provider_account', 'provider_network', 'status', 'tenant', 'tenant_group', + 'description', 'comments', 'tags', 'created', 'last_updated', + ) + default_columns = ( + 'pk', 'cid', 'provider', 'provider_account', 'provider_network', 'status', 'tenant', 'termination_count', + 'description', + ) + + +class VirtualCircuitTerminationTable(NetBoxTable): + virtual_circuit = tables.Column( + verbose_name=_('Virtual circuit'), + linkify=True + ) + provider = tables.Column( + accessor=tables.A('virtual_circuit__provider_network__provider'), + verbose_name=_('Provider'), + linkify=True + ) + provider_network = tables.Column( + accessor=tables.A('virtual_circuit__provider_network'), + linkify=True, + verbose_name=_('Provider network') + ) + provider_account = tables.Column( + linkify=True, + verbose_name=_('Account') + ) + role = columns.ChoiceFieldColumn() + device = tables.Column( + accessor=tables.A('interface__device'), + linkify=True, + verbose_name=_('Device') + ) + interface = tables.Column( + verbose_name=_('Interface'), + linkify=True + ) + + class Meta(NetBoxTable.Meta): + model = VirtualCircuitTermination + fields = ( + 'pk', 'id', 'virtual_circuit', 'provider', 'provider_network', 'provider_account', 'role', 'interfaces', + 'description', 'created', 'last_updated', 'actions', + ) + default_columns = ( + 'pk', 'id', 'virtual_circuit', 'role', 'device', 'interface', 'description', + ) diff --git a/netbox/circuits/tests/test_api.py b/netbox/circuits/tests/test_api.py index 1b2e9f3f8..92fbbdedf 100644 --- a/netbox/circuits/tests/test_api.py +++ b/netbox/circuits/tests/test_api.py @@ -2,7 +2,8 @@ from django.urls import reverse from circuits.choices import * from circuits.models import * -from dcim.models import Site +from dcim.choices import InterfaceTypeChoices +from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site from ipam.models import ASN, RIR from utilities.testing import APITestCase, APIViewTestCases @@ -120,9 +121,15 @@ class CircuitTest(APIViewTestCases.APIViewTestCase): CircuitType.objects.bulk_create(circuit_types) circuits = ( - Circuit(cid='Circuit 1', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0]), - Circuit(cid='Circuit 2', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0]), - Circuit(cid='Circuit 3', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0]), + Circuit( + cid='Circuit 1', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0] + ), + Circuit( + cid='Circuit 2', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0] + ), + Circuit( + cid='Circuit 3', provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0] + ), ) Circuit.objects.bulk_create(circuits) @@ -397,3 +404,240 @@ class ProviderNetworkTest(APIViewTestCases.APIViewTestCase): 'provider': providers[1].pk, 'description': 'New description', } + + +class VirtualCircuitTest(APIViewTestCases.APIViewTestCase): + model = VirtualCircuit + brief_fields = ['cid', 'description', 'display', 'id', 'provider_network', 'url'] + bulk_update_data = { + 'status': 'planned', + } + + @classmethod + def setUpTestData(cls): + provider = Provider.objects.create(name='Provider 1', slug='provider-1') + provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1') + provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1') + + virtual_circuits = ( + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 1' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 2' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 3' + ), + ) + VirtualCircuit.objects.bulk_create(virtual_circuits) + + cls.create_data = [ + { + 'cid': 'Virtual Circuit 4', + 'provider_network': provider_network.pk, + 'provider_account': provider_account.pk, + 'status': CircuitStatusChoices.STATUS_PLANNED, + }, + { + 'cid': 'Virtual Circuit 5', + 'provider_network': provider_network.pk, + 'provider_account': provider_account.pk, + 'status': CircuitStatusChoices.STATUS_PLANNED, + }, + { + 'cid': 'Virtual Circuit 6', + 'provider_network': provider_network.pk, + 'provider_account': provider_account.pk, + 'status': CircuitStatusChoices.STATUS_PLANNED, + }, + ] + + +class VirtualCircuitTerminationTest(APIViewTestCases.APIViewTestCase): + model = VirtualCircuitTermination + brief_fields = ['description', 'display', 'id', 'interface', 'role', 'url', 'virtual_circuit'] + bulk_update_data = { + 'description': 'New description', + } + + @classmethod + def setUpTestData(cls): + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') + device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1') + device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + site = Site.objects.create(name='Site 1', slug='site-1') + + devices = ( + Device(site=site, name='hub', device_type=device_type, role=device_role), + Device(site=site, name='spoke1', device_type=device_type, role=device_role), + Device(site=site, name='spoke2', device_type=device_type, role=device_role), + Device(site=site, name='spoke3', device_type=device_type, role=device_role), + ) + Device.objects.bulk_create(devices) + + physical_interfaces = ( + Interface(device=devices[0], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[1], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[2], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[3], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + ) + Interface.objects.bulk_create(physical_interfaces) + + virtual_interfaces = ( + # Point-to-point VCs + Interface( + device=devices[0], + name='eth0.1', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[0], + name='eth0.2', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[0], + name='eth0.3', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[1], + name='eth0.1', + parent=physical_interfaces[1], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[2], + name='eth0.1', + parent=physical_interfaces[2], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[3], + name='eth0.1', + parent=physical_interfaces[3], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + + # Hub and spoke VCs + Interface( + device=devices[0], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[1], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[2], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[3], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + ) + Interface.objects.bulk_create(virtual_interfaces) + + provider = Provider.objects.create(name='Provider 1', slug='provider-1') + provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1') + provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1') + + virtual_circuits = ( + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 1' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 2' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 3' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 4' + ), + ) + VirtualCircuit.objects.bulk_create(virtual_circuits) + + virtual_circuit_terminations = ( + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[0] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[3] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[1] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[4] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[2] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[5] + ), + ) + VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations) + + cls.create_data = [ + { + 'virtual_circuit': virtual_circuits[3].pk, + 'role': VirtualCircuitTerminationRoleChoices.ROLE_HUB, + 'interface': virtual_interfaces[6].pk + }, + { + 'virtual_circuit': virtual_circuits[3].pk, + 'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE, + 'interface': virtual_interfaces[7].pk + }, + { + 'virtual_circuit': virtual_circuits[3].pk, + 'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE, + 'interface': virtual_interfaces[8].pk + }, + { + 'virtual_circuit': virtual_circuits[3].pk, + 'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE, + 'interface': virtual_interfaces[9].pk + }, + ] diff --git a/netbox/circuits/tests/test_filtersets.py b/netbox/circuits/tests/test_filtersets.py index 0dbc7172b..6b7866665 100644 --- a/netbox/circuits/tests/test_filtersets.py +++ b/netbox/circuits/tests/test_filtersets.py @@ -3,7 +3,8 @@ from django.test import TestCase from circuits.choices import * from circuits.filtersets import * from circuits.models import * -from dcim.models import Cable, Region, Site, SiteGroup +from dcim.choices import InterfaceTypeChoices +from dcim.models import Cable, Device, DeviceRole, DeviceType, Interface, Manufacturer, Region, Site, SiteGroup from ipam.models import ASN, RIR from netbox.choices import DistanceUnitChoices from tenancy.models import Tenant, TenantGroup @@ -225,12 +226,80 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests): ProviderNetwork.objects.bulk_create(provider_networks) circuits = ( - Circuit(provider=providers[0], provider_account=provider_accounts[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 1', install_date='2020-01-01', termination_date='2021-01-01', commit_rate=1000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar1', distance=10, distance_unit=DistanceUnitChoices.UNIT_FOOT), - Circuit(provider=providers[0], provider_account=provider_accounts[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 2', install_date='2020-01-02', termination_date='2021-01-02', commit_rate=2000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar2', distance=20, distance_unit=DistanceUnitChoices.UNIT_METER), - Circuit(provider=providers[0], provider_account=provider_accounts[1], tenant=tenants[1], type=circuit_types[0], cid='Test Circuit 3', install_date='2020-01-03', termination_date='2021-01-03', commit_rate=3000, status=CircuitStatusChoices.STATUS_PLANNED, distance=30, distance_unit=DistanceUnitChoices.UNIT_METER), - Circuit(provider=providers[1], provider_account=provider_accounts[1], tenant=tenants[1], type=circuit_types[1], cid='Test Circuit 4', install_date='2020-01-04', termination_date='2021-01-04', commit_rate=4000, status=CircuitStatusChoices.STATUS_PLANNED), - Circuit(provider=providers[1], provider_account=provider_accounts[2], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 5', install_date='2020-01-05', termination_date='2021-01-05', commit_rate=5000, status=CircuitStatusChoices.STATUS_OFFLINE), - Circuit(provider=providers[1], provider_account=provider_accounts[2], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 6', install_date='2020-01-06', termination_date='2021-01-06', commit_rate=6000, status=CircuitStatusChoices.STATUS_OFFLINE), + Circuit( + provider=providers[0], + provider_account=provider_accounts[0], + tenant=tenants[0], + type=circuit_types[0], + cid='Test Circuit 1', + install_date='2020-01-01', + termination_date='2021-01-01', + commit_rate=1000, + status=CircuitStatusChoices.STATUS_ACTIVE, + description='foobar1', + distance=10, + distance_unit=DistanceUnitChoices.UNIT_FOOT, + ), + Circuit( + provider=providers[0], + provider_account=provider_accounts[0], + tenant=tenants[0], + type=circuit_types[0], + cid='Test Circuit 2', + install_date='2020-01-02', + termination_date='2021-01-02', + commit_rate=2000, + status=CircuitStatusChoices.STATUS_ACTIVE, + description='foobar2', + distance=20, + distance_unit=DistanceUnitChoices.UNIT_METER, + ), + Circuit( + provider=providers[0], + provider_account=provider_accounts[1], + tenant=tenants[1], + type=circuit_types[0], + cid='Test Circuit 3', + install_date='2020-01-03', + termination_date='2021-01-03', + commit_rate=3000, + status=CircuitStatusChoices.STATUS_PLANNED, + distance=30, + distance_unit=DistanceUnitChoices.UNIT_METER, + ), + Circuit( + provider=providers[1], + provider_account=provider_accounts[1], + tenant=tenants[1], + type=circuit_types[1], + cid='Test Circuit 4', + install_date='2020-01-04', + termination_date='2021-01-04', + commit_rate=4000, + status=CircuitStatusChoices.STATUS_PLANNED, + ), + Circuit( + provider=providers[1], + provider_account=provider_accounts[2], + tenant=tenants[2], + type=circuit_types[1], + cid='Test Circuit 5', + install_date='2020-01-05', + termination_date='2021-01-05', + commit_rate=5000, + status=CircuitStatusChoices.STATUS_OFFLINE, + ), + Circuit( + provider=providers[1], + provider_account=provider_accounts[2], + tenant=tenants[2], + type=circuit_types[1], + cid='Test Circuit 6', + install_date='2020-01-06', + termination_date='2021-01-06', + commit_rate=6000, + status=CircuitStatusChoices.STATUS_OFFLINE, + ), ) Circuit.objects.bulk_create(circuits) @@ -386,18 +455,64 @@ class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests): ) Circuit.objects.bulk_create(circuits) - circuit_terminations = (( - CircuitTermination(circuit=circuits[0], termination=sites[0], term_side='A', port_speed=1000, upstream_speed=1000, xconnect_id='ABC', description='foobar1'), - CircuitTermination(circuit=circuits[0], termination=sites[1], term_side='Z', port_speed=1000, upstream_speed=1000, xconnect_id='DEF', description='foobar2'), - CircuitTermination(circuit=circuits[1], termination=sites[1], term_side='A', port_speed=2000, upstream_speed=2000, xconnect_id='GHI'), - CircuitTermination(circuit=circuits[1], termination=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'), - CircuitTermination(circuit=circuits[2], termination=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'), - CircuitTermination(circuit=circuits[2], termination=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'), + circuit_terminations = ( + CircuitTermination( + circuit=circuits[0], + termination=sites[0], + term_side='A', + port_speed=1000, + upstream_speed=1000, + xconnect_id='ABC', + description='foobar1', + ), + CircuitTermination( + circuit=circuits[0], + termination=sites[1], + term_side='Z', + port_speed=1000, + upstream_speed=1000, + xconnect_id='DEF', + description='foobar2', + ), + CircuitTermination( + circuit=circuits[1], + termination=sites[1], + term_side='A', + port_speed=2000, + upstream_speed=2000, + xconnect_id='GHI', + ), + CircuitTermination( + circuit=circuits[1], + termination=sites[2], + term_side='Z', + port_speed=2000, + upstream_speed=2000, + xconnect_id='JKL', + ), + CircuitTermination( + circuit=circuits[2], + termination=sites[2], + term_side='A', + port_speed=3000, + upstream_speed=3000, + xconnect_id='MNO', + ), + CircuitTermination( + circuit=circuits[2], + termination=sites[0], + term_side='Z', + port_speed=3000, + upstream_speed=3000, + xconnect_id='PQR', + ), CircuitTermination(circuit=circuits[3], termination=provider_networks[0], term_side='A'), CircuitTermination(circuit=circuits[4], termination=provider_networks[1], term_side='A'), CircuitTermination(circuit=circuits[5], termination=provider_networks[2], term_side='A'), - CircuitTermination(circuit=circuits[6], termination=provider_networks[0], term_side='A', mark_connected=True), - )) + CircuitTermination( + circuit=circuits[6], termination=provider_networks[0], term_side='A', mark_connected=True + ), + ) for ct in circuit_terminations: ct.save() @@ -678,3 +793,293 @@ class ProviderAccountTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) params = {'provider': [providers[0].slug, providers[1].slug]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + +class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests): + queryset = VirtualCircuit.objects.all() + filterset = VirtualCircuitFilterSet + + @classmethod + def setUpTestData(cls): + + tenant_groups = ( + TenantGroup(name='Tenant group 1', slug='tenant-group-1'), + TenantGroup(name='Tenant group 2', slug='tenant-group-2'), + TenantGroup(name='Tenant group 3', slug='tenant-group-3'), + ) + for tenantgroup in tenant_groups: + tenantgroup.save() + + tenants = ( + Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]), + Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]), + Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]), + ) + Tenant.objects.bulk_create(tenants) + + providers = ( + Provider(name='Provider 1', slug='provider-1'), + Provider(name='Provider 2', slug='provider-2'), + Provider(name='Provider 3', slug='provider-3'), + ) + Provider.objects.bulk_create(providers) + + provider_accounts = ( + ProviderAccount(name='Provider Account 1', provider=providers[0], account='A'), + ProviderAccount(name='Provider Account 2', provider=providers[1], account='B'), + ProviderAccount(name='Provider Account 3', provider=providers[2], account='C'), + ) + ProviderAccount.objects.bulk_create(provider_accounts) + + provider_networks = ( + ProviderNetwork(name='Provider Network 1', provider=providers[0]), + ProviderNetwork(name='Provider Network 2', provider=providers[1]), + ProviderNetwork(name='Provider Network 3', provider=providers[2]), + ) + ProviderNetwork.objects.bulk_create(provider_networks) + + virutal_circuits = ( + VirtualCircuit( + provider_network=provider_networks[0], + provider_account=provider_accounts[0], + tenant=tenants[0], + cid='Virtual Circuit 1', + status=CircuitStatusChoices.STATUS_PLANNED, + description='virtualcircuit1', + ), + VirtualCircuit( + provider_network=provider_networks[1], + provider_account=provider_accounts[1], + tenant=tenants[1], + cid='Virtual Circuit 2', + status=CircuitStatusChoices.STATUS_ACTIVE, + description='virtualcircuit2', + ), + VirtualCircuit( + provider_network=provider_networks[2], + provider_account=provider_accounts[2], + tenant=tenants[2], + cid='Virtual Circuit 3', + status=CircuitStatusChoices.STATUS_DEPROVISIONING, + description='virtualcircuit3', + ), + ) + VirtualCircuit.objects.bulk_create(virutal_circuits) + + def test_q(self): + params = {'q': 'virtualcircuit1'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + def test_cid(self): + params = {'cid': ['Virtual Circuit 1', 'Virtual Circuit 2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_provider(self): + providers = Provider.objects.all()[:2] + params = {'provider_id': [providers[0].pk, providers[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'provider': [providers[0].slug, providers[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_provider_account(self): + provider_accounts = ProviderAccount.objects.all()[:2] + params = {'provider_account_id': [provider_accounts[0].pk, provider_accounts[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_provider_network(self): + provider_networks = ProviderNetwork.objects.all()[:2] + params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_status(self): + params = {'status': [CircuitStatusChoices.STATUS_ACTIVE, CircuitStatusChoices.STATUS_PLANNED]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_description(self): + params = {'description': ['virtualcircuit1', 'virtualcircuit2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_tenant(self): + tenants = Tenant.objects.all()[:2] + params = {'tenant_id': [tenants[0].pk, tenants[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'tenant': [tenants[0].slug, tenants[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_tenant_group(self): + tenant_groups = TenantGroup.objects.all()[:2] + params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + +class VirtualCircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests): + queryset = VirtualCircuitTermination.objects.all() + filterset = VirtualCircuitTerminationFilterSet + + @classmethod + def setUpTestData(cls): + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') + device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1') + device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + site = Site.objects.create(name='Site 1', slug='site-1') + + devices = ( + Device(site=site, name='Device 1', device_type=device_type, role=device_role), + Device(site=site, name='Device 2', device_type=device_type, role=device_role), + Device(site=site, name='Device 3', device_type=device_type, role=device_role), + ) + Device.objects.bulk_create(devices) + + virtual_interfaces = ( + # Device 1 + Interface( + device=devices[0], + name='eth0.1', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[0], + name='eth0.2', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + # Device 2 + Interface( + device=devices[1], + name='eth0.1', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[1], + name='eth0.2', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + # Device 3 + Interface( + device=devices[2], + name='eth0.1', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[2], + name='eth0.2', + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + ) + Interface.objects.bulk_create(virtual_interfaces) + + providers = ( + Provider(name='Provider 1', slug='provider-1'), + Provider(name='Provider 2', slug='provider-2'), + Provider(name='Provider 3', slug='provider-3'), + ) + Provider.objects.bulk_create(providers) + provider_networks = ( + ProviderNetwork(provider=providers[0], name='Provider Network 1'), + ProviderNetwork(provider=providers[1], name='Provider Network 2'), + ProviderNetwork(provider=providers[2], name='Provider Network 3'), + ) + ProviderNetwork.objects.bulk_create(provider_networks) + provider_accounts = ( + ProviderAccount(provider=providers[0], account='Provider Account 1'), + ProviderAccount(provider=providers[1], account='Provider Account 2'), + ProviderAccount(provider=providers[2], account='Provider Account 3'), + ) + ProviderAccount.objects.bulk_create(provider_accounts) + + virtual_circuits = ( + VirtualCircuit( + provider_network=provider_networks[0], + provider_account=provider_accounts[0], + cid='Virtual Circuit 1' + ), + VirtualCircuit( + provider_network=provider_networks[1], + provider_account=provider_accounts[1], + cid='Virtual Circuit 2' + ), + VirtualCircuit( + provider_network=provider_networks[2], + provider_account=provider_accounts[2], + cid='Virtual Circuit 3' + ), + ) + VirtualCircuit.objects.bulk_create(virtual_circuits) + + virtual_circuit_terminations = ( + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_HUB, + interface=virtual_interfaces[0], + description='termination1' + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_SPOKE, + interface=virtual_interfaces[3], + description='termination2' + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[1], + description='termination3' + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[4], + description='termination4' + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[2], + description='termination5' + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[5], + description='termination6' + ), + ) + VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations) + + def test_q(self): + params = {'q': 'termination1'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + def test_description(self): + params = {'description': ['termination1', 'termination2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_virtual_circuit_id(self): + virtual_circuits = VirtualCircuit.objects.filter()[:2] + params = {'virtual_circuit_id': [virtual_circuits[0].pk, virtual_circuits[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_provider(self): + providers = Provider.objects.all()[:2] + params = {'provider_id': [providers[0].pk, providers[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'provider': [providers[0].slug, providers[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_provider_network(self): + provider_networks = ProviderNetwork.objects.all()[:2] + params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_provider_account(self): + provider_accounts = ProviderAccount.objects.all()[:2] + params = {'provider_account_id': [provider_accounts[0].pk, provider_accounts[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'provider_account': [provider_accounts[0].account, provider_accounts[1].account]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_interface(self): + interfaces = Interface.objects.all()[:2] + params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) diff --git a/netbox/circuits/tests/test_views.py b/netbox/circuits/tests/test_views.py index f6c626443..3a9bd4dff 100644 --- a/netbox/circuits/tests/test_views.py +++ b/netbox/circuits/tests/test_views.py @@ -7,7 +7,8 @@ from django.urls import reverse from circuits.choices import * from circuits.models import * from core.models import ObjectType -from dcim.models import Cable, Interface, Site +from dcim.choices import InterfaceTypeChoices +from dcim.models import Cable, Device, DeviceRole, DeviceType, Interface, Manufacturer, Site from ipam.models import ASN, RIR from netbox.choices import ImportFormatChoices from users.models import ObjectPermission @@ -140,9 +141,15 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase): CircuitType.objects.bulk_create(circuittypes) circuits = ( - Circuit(cid='Circuit 1', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0]), - Circuit(cid='Circuit 2', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0]), - Circuit(cid='Circuit 3', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0]), + Circuit( + cid='Circuit 1', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0] + ), + Circuit( + cid='Circuit 2', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0] + ), + Circuit( + cid='Circuit 3', provider=providers[0], provider_account=provider_accounts[0], type=circuittypes[0] + ), ) Circuit.objects.bulk_create(circuits) @@ -341,7 +348,7 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase): } -class TestCase(ViewTestCases.PrimaryObjectViewTestCase): +class CircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase): model = CircuitTermination @classmethod @@ -518,3 +525,319 @@ class CircuitGroupAssignmentTestCase( cls.bulk_edit_data = { 'priority': CircuitPriorityChoices.PRIORITY_INACTIVE, } + + +class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase): + model = VirtualCircuit + + def setUp(self): + super().setUp() + + self.add_permissions( + 'circuits.add_virtualcircuittermination', + ) + + @classmethod + def setUpTestData(cls): + provider = Provider.objects.create(name='Provider 1', slug='provider-1') + provider_networks = ( + ProviderNetwork(provider=provider, name='Provider Network 1'), + ProviderNetwork(provider=provider, name='Provider Network 2'), + ) + ProviderNetwork.objects.bulk_create(provider_networks) + provider_accounts = ( + ProviderAccount(provider=provider, account='Provider Account 1'), + ProviderAccount(provider=provider, account='Provider Account 2'), + ) + ProviderAccount.objects.bulk_create(provider_accounts) + + virtual_circuits = ( + VirtualCircuit( + provider_network=provider_networks[0], + provider_account=provider_accounts[0], + cid='Virtual Circuit 1' + ), + VirtualCircuit( + provider_network=provider_networks[0], + provider_account=provider_accounts[0], + cid='Virtual Circuit 2' + ), + VirtualCircuit( + provider_network=provider_networks[0], + provider_account=provider_accounts[0], + cid='Virtual Circuit 3' + ), + ) + VirtualCircuit.objects.bulk_create(virtual_circuits) + + device = create_test_device('Device 1') + interfaces = ( + Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL), + Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_VIRTUAL), + Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_VIRTUAL), + ) + Interface.objects.bulk_create(interfaces) + + tags = create_tags('Alpha', 'Bravo', 'Charlie') + + cls.form_data = { + 'cid': 'Virtual Circuit X', + 'provider_network': provider_networks[1].pk, + 'provider_account': provider_accounts[1].pk, + 'status': CircuitStatusChoices.STATUS_PLANNED, + 'description': 'A new virtual circuit', + 'comments': 'Some comments', + 'tags': [t.pk for t in tags], + } + + cls.csv_data = ( + "cid,provider_network,provider_account,status", + f"Virtual Circuit 4,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}", + f"Virtual Circuit 5,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}", + f"Virtual Circuit 6,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}", + ) + + cls.csv_update_data = ( + "id,cid,description,status", + f"{virtual_circuits[0].pk},Virtual Circuit A,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", + f"{virtual_circuits[1].pk},Virtual Circuit B,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", + f"{virtual_circuits[2].pk},Virtual Circuit C,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", + ) + + cls.bulk_edit_data = { + 'provider_network': provider_networks[1].pk, + 'provider_account': provider_accounts[1].pk, + 'status': CircuitStatusChoices.STATUS_DECOMMISSIONED, + 'description': 'New description', + 'comments': 'New comments', + } + + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[]) + def test_bulk_import_objects_with_terminations(self): + interfaces = Interface.objects.filter(type=InterfaceTypeChoices.TYPE_VIRTUAL) + json_data = f""" + [ + {{ + "cid": "Virtual Circuit 7", + "provider_network": "Provider Network 1", + "status": "active", + "terminations": [ + {{ + "role": "hub", + "interface": {interfaces[0].pk} + }}, + {{ + "role": "spoke", + "interface": {interfaces[1].pk} + }}, + {{ + "role": "spoke", + "interface": {interfaces[2].pk} + }} + ] + }} + ] + """ + + initial_count = self._get_queryset().count() + data = { + 'data': json_data, + 'format': ImportFormatChoices.JSON, + } + + # Assign model-level permission + obj_perm = ObjectPermission( + name='Test permission', + actions=['add'] + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model)) + + # Try GET with model-level permission + self.assertHttpStatus(self.client.get(self._get_url('import')), 200) + + # Test POST with permission + self.assertHttpStatus(self.client.post(self._get_url('import'), data), 302) + self.assertEqual(self._get_queryset().count(), initial_count + 1) + + +class VirtualCircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase): + model = VirtualCircuitTermination + + @classmethod + def setUpTestData(cls): + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') + device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1') + device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + site = Site.objects.create(name='Site 1', slug='site-1') + + devices = ( + Device(site=site, name='hub', device_type=device_type, role=device_role), + Device(site=site, name='spoke1', device_type=device_type, role=device_role), + Device(site=site, name='spoke2', device_type=device_type, role=device_role), + Device(site=site, name='spoke3', device_type=device_type, role=device_role), + ) + Device.objects.bulk_create(devices) + + physical_interfaces = ( + Interface(device=devices[0], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[1], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[2], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[3], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + ) + Interface.objects.bulk_create(physical_interfaces) + + virtual_interfaces = ( + # Point-to-point VCs + Interface( + device=devices[0], + name='eth0.1', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[0], + name='eth0.2', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[0], + name='eth0.3', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[1], + name='eth0.1', + parent=physical_interfaces[1], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[2], + name='eth0.1', + parent=physical_interfaces[2], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[3], + name='eth0.1', + parent=physical_interfaces[3], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + + # Hub and spoke VCs + Interface( + device=devices[0], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[1], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[2], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + Interface( + device=devices[3], + name='eth0.9', + parent=physical_interfaces[0], + type=InterfaceTypeChoices.TYPE_VIRTUAL + ), + ) + Interface.objects.bulk_create(virtual_interfaces) + + provider = Provider.objects.create(name='Provider 1', slug='provider-1') + provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1') + provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1') + + virtual_circuits = ( + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 1' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 2' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 3' + ), + VirtualCircuit( + provider_network=provider_network, + provider_account=provider_account, + cid='Virtual Circuit 4' + ), + ) + VirtualCircuit.objects.bulk_create(virtual_circuits) + + virtual_circuit_terminations = ( + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[0] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[0], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[3] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[1] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[1], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[4] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[2] + ), + VirtualCircuitTermination( + virtual_circuit=virtual_circuits[2], + role=VirtualCircuitTerminationRoleChoices.ROLE_PEER, + interface=virtual_interfaces[5] + ), + ) + VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations) + + cls.form_data = { + 'virtual_circuit': virtual_circuits[3].pk, + 'role': VirtualCircuitTerminationRoleChoices.ROLE_HUB, + 'interface': virtual_interfaces[6].pk + } + + cls.csv_data = ( + "virtual_circuit,role,interface,description", + f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_HUB},{virtual_interfaces[6].pk},Hub", + f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[7].pk},Spoke 1", + f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[8].pk},Spoke 2", + f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[9].pk},Spoke 3", + ) + + cls.csv_update_data = ( + "id,role,description", + f"{virtual_circuit_terminations[0].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description", + f"{virtual_circuit_terminations[1].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description", + f"{virtual_circuit_terminations[2].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description", + ) + + cls.bulk_edit_data = { + 'description': 'New description', + } diff --git a/netbox/circuits/urls.py b/netbox/circuits/urls.py index 2171d49be..56ba5eb8a 100644 --- a/netbox/circuits/urls.py +++ b/netbox/circuits/urls.py @@ -5,69 +5,68 @@ from . import views app_name = 'circuits' urlpatterns = [ - - # Providers - path('providers/', views.ProviderListView.as_view(), name='provider_list'), - path('providers/add/', views.ProviderEditView.as_view(), name='provider_add'), - path('providers/import/', views.ProviderBulkImportView.as_view(), name='provider_import'), - path('providers/edit/', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'), - path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'), + path('providers/', include(get_model_urls('circuits', 'provider', detail=False))), path('providers//', include(get_model_urls('circuits', 'provider'))), - # Provider accounts - path('provider-accounts/', views.ProviderAccountListView.as_view(), name='provideraccount_list'), - path('provider-accounts/add/', views.ProviderAccountEditView.as_view(), name='provideraccount_add'), - path('provider-accounts/import/', views.ProviderAccountBulkImportView.as_view(), name='provideraccount_import'), - path('provider-accounts/edit/', views.ProviderAccountBulkEditView.as_view(), name='provideraccount_bulk_edit'), - path('provider-accounts/delete/', views.ProviderAccountBulkDeleteView.as_view(), name='provideraccount_bulk_delete'), + path('provider-accounts/', include(get_model_urls('circuits', 'provideraccount', detail=False))), path('provider-accounts//', include(get_model_urls('circuits', 'provideraccount'))), - # Provider networks - path('provider-networks/', views.ProviderNetworkListView.as_view(), name='providernetwork_list'), - path('provider-networks/add/', views.ProviderNetworkEditView.as_view(), name='providernetwork_add'), - path('provider-networks/import/', views.ProviderNetworkBulkImportView.as_view(), name='providernetwork_import'), - path('provider-networks/edit/', views.ProviderNetworkBulkEditView.as_view(), name='providernetwork_bulk_edit'), - path('provider-networks/delete/', views.ProviderNetworkBulkDeleteView.as_view(), name='providernetwork_bulk_delete'), + path('provider-networks/', include(get_model_urls('circuits', 'providernetwork', detail=False))), path('provider-networks//', include(get_model_urls('circuits', 'providernetwork'))), - # Circuit types - path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'), - path('circuit-types/add/', views.CircuitTypeEditView.as_view(), name='circuittype_add'), - path('circuit-types/import/', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'), - path('circuit-types/edit/', views.CircuitTypeBulkEditView.as_view(), name='circuittype_bulk_edit'), - path('circuit-types/delete/', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'), + path('circuit-types/', include(get_model_urls('circuits', 'circuittype', detail=False))), path('circuit-types//', include(get_model_urls('circuits', 'circuittype'))), - # Circuits - path('circuits/', views.CircuitListView.as_view(), name='circuit_list'), - path('circuits/add/', views.CircuitEditView.as_view(), name='circuit_add'), - path('circuits/import/', views.CircuitBulkImportView.as_view(), name='circuit_import'), - path('circuits/edit/', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'), - path('circuits/delete/', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'), - path('circuits//terminations/swap/', views.CircuitSwapTerminations.as_view(), name='circuit_terminations_swap'), + path('circuits/', include(get_model_urls('circuits', 'circuit', detail=False))), + path( + 'circuits//terminations/swap/', + views.CircuitSwapTerminations.as_view(), + name='circuit_terminations_swap' + ), path('circuits//', include(get_model_urls('circuits', 'circuit'))), - # Circuit terminations - path('circuit-terminations/', views.CircuitTerminationListView.as_view(), name='circuittermination_list'), - path('circuit-terminations/add/', views.CircuitTerminationEditView.as_view(), name='circuittermination_add'), - path('circuit-terminations/import/', views.CircuitTerminationBulkImportView.as_view(), name='circuittermination_import'), - path('circuit-terminations/edit/', views.CircuitTerminationBulkEditView.as_view(), name='circuittermination_bulk_edit'), - path('circuit-terminations/delete/', views.CircuitTerminationBulkDeleteView.as_view(), name='circuittermination_bulk_delete'), + path('circuit-terminations/', include(get_model_urls('circuits', 'circuittermination', detail=False))), path('circuit-terminations//', include(get_model_urls('circuits', 'circuittermination'))), - # Circuit Groups - path('circuit-groups/', views.CircuitGroupListView.as_view(), name='circuitgroup_list'), - path('circuit-groups/add/', views.CircuitGroupEditView.as_view(), name='circuitgroup_add'), - path('circuit-groups/import/', views.CircuitGroupBulkImportView.as_view(), name='circuitgroup_import'), - path('circuit-groups/edit/', views.CircuitGroupBulkEditView.as_view(), name='circuitgroup_bulk_edit'), - path('circuit-groups/delete/', views.CircuitGroupBulkDeleteView.as_view(), name='circuitgroup_bulk_delete'), + path('circuit-groups/', include(get_model_urls('circuits', 'circuitgroup', detail=False))), path('circuit-groups//', include(get_model_urls('circuits', 'circuitgroup'))), - # Circuit Group Assignments - path('circuit-group-assignments/', views.CircuitGroupAssignmentListView.as_view(), name='circuitgroupassignment_list'), - path('circuit-group-assignments/add/', views.CircuitGroupAssignmentEditView.as_view(), name='circuitgroupassignment_add'), - path('circuit-group-assignments/import/', views.CircuitGroupAssignmentBulkImportView.as_view(), name='circuitgroupassignment_import'), - path('circuit-group-assignments/edit/', views.CircuitGroupAssignmentBulkEditView.as_view(), name='circuitgroupassignment_bulk_edit'), - path('circuit-group-assignments/delete/', views.CircuitGroupAssignmentBulkDeleteView.as_view(), name='circuitgroupassignment_bulk_delete'), + path('circuit-group-assignments/', include(get_model_urls('circuits', 'circuitgroupassignment', detail=False))), path('circuit-group-assignments//', include(get_model_urls('circuits', 'circuitgroupassignment'))), + + # Virtual circuits + path('virtual-circuits/', views.VirtualCircuitListView.as_view(), name='virtualcircuit_list'), + path('virtual-circuits/add/', views.VirtualCircuitEditView.as_view(), name='virtualcircuit_add'), + path('virtual-circuits/import/', views.VirtualCircuitBulkImportView.as_view(), name='virtualcircuit_import'), + path('virtual-circuits/edit/', views.VirtualCircuitBulkEditView.as_view(), name='virtualcircuit_bulk_edit'), + path('virtual-circuits/delete/', views.VirtualCircuitBulkDeleteView.as_view(), name='virtualcircuit_bulk_delete'), + path('virtual-circuits//', include(get_model_urls('circuits', 'virtualcircuit'))), + + # Virtual circuit terminations + path( + 'virtual-circuit-terminations/', + views.VirtualCircuitTerminationListView.as_view(), + name='virtualcircuittermination_list', + ), + path( + 'virtual-circuit-terminations/add/', + views.VirtualCircuitTerminationEditView.as_view(), + name='virtualcircuittermination_add', + ), + path( + 'virtual-circuit-terminations/import/', + views.VirtualCircuitTerminationBulkImportView.as_view(), + name='virtualcircuittermination_import', + ), + path( + 'virtual-circuit-terminations/edit/', + views.VirtualCircuitTerminationBulkEditView.as_view(), + name='virtualcircuittermination_bulk_edit', + ), + path( + 'virtual-circuit-terminations/delete/', + views.VirtualCircuitTerminationBulkDeleteView.as_view(), + name='virtualcircuittermination_bulk_delete', + ), + path('virtual-circuit-terminations//', include(get_model_urls('circuits', 'virtualcircuittermination'))), ] diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 4059065bf..7410d0a8f 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -17,6 +17,7 @@ from .models import * # Providers # +@register_model_view(Provider, 'list', path='', detail=False) class ProviderListView(generic.ObjectListView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') @@ -36,6 +37,7 @@ class ProviderView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Provider, 'add', detail=False) @register_model_view(Provider, 'edit') class ProviderEditView(generic.ObjectEditView): queryset = Provider.objects.all() @@ -47,11 +49,13 @@ class ProviderDeleteView(generic.ObjectDeleteView): queryset = Provider.objects.all() +@register_model_view(Provider, 'import', detail=False) class ProviderBulkImportView(generic.BulkImportView): queryset = Provider.objects.all() model_form = forms.ProviderImportForm +@register_model_view(Provider, 'bulk_edit', path='edit', detail=False) class ProviderBulkEditView(generic.BulkEditView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') @@ -61,6 +65,7 @@ class ProviderBulkEditView(generic.BulkEditView): form = forms.ProviderBulkEditForm +@register_model_view(Provider, 'bulk_delete', path='delete', detail=False) class ProviderBulkDeleteView(generic.BulkDeleteView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') @@ -78,6 +83,7 @@ class ProviderContactsView(ObjectContactsView): # ProviderAccounts # +@register_model_view(ProviderAccount, 'list', path='', detail=False) class ProviderAccountListView(generic.ObjectListView): queryset = ProviderAccount.objects.annotate( count_circuits=count_related(Circuit, 'provider_account') @@ -97,6 +103,7 @@ class ProviderAccountView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ProviderAccount, 'add', detail=False) @register_model_view(ProviderAccount, 'edit') class ProviderAccountEditView(generic.ObjectEditView): queryset = ProviderAccount.objects.all() @@ -108,12 +115,14 @@ class ProviderAccountDeleteView(generic.ObjectDeleteView): queryset = ProviderAccount.objects.all() +@register_model_view(ProviderAccount, 'import', detail=False) class ProviderAccountBulkImportView(generic.BulkImportView): queryset = ProviderAccount.objects.all() model_form = forms.ProviderAccountImportForm table = tables.ProviderAccountTable +@register_model_view(ProviderAccount, 'bulk_edit', path='edit', detail=False) class ProviderAccountBulkEditView(generic.BulkEditView): queryset = ProviderAccount.objects.annotate( count_circuits=count_related(Circuit, 'provider_account') @@ -123,6 +132,7 @@ class ProviderAccountBulkEditView(generic.BulkEditView): form = forms.ProviderAccountBulkEditForm +@register_model_view(ProviderAccount, 'bulk_delete', path='delete', detail=False) class ProviderAccountBulkDeleteView(generic.BulkDeleteView): queryset = ProviderAccount.objects.annotate( count_circuits=count_related(Circuit, 'provider_account') @@ -140,6 +150,7 @@ class ProviderAccountContactsView(ObjectContactsView): # Provider networks # +@register_model_view(ProviderNetwork, 'list', path='', detail=False) class ProviderNetworkListView(generic.ObjectListView): queryset = ProviderNetwork.objects.all() filterset = filtersets.ProviderNetworkFilterSet @@ -166,6 +177,7 @@ class ProviderNetworkView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ProviderNetwork, 'add', detail=False) @register_model_view(ProviderNetwork, 'edit') class ProviderNetworkEditView(generic.ObjectEditView): queryset = ProviderNetwork.objects.all() @@ -177,11 +189,13 @@ class ProviderNetworkDeleteView(generic.ObjectDeleteView): queryset = ProviderNetwork.objects.all() +@register_model_view(ProviderNetwork, 'import', detail=False) class ProviderNetworkBulkImportView(generic.BulkImportView): queryset = ProviderNetwork.objects.all() model_form = forms.ProviderNetworkImportForm +@register_model_view(ProviderNetwork, 'bulk_edit', path='edit', detail=False) class ProviderNetworkBulkEditView(generic.BulkEditView): queryset = ProviderNetwork.objects.all() filterset = filtersets.ProviderNetworkFilterSet @@ -189,6 +203,7 @@ class ProviderNetworkBulkEditView(generic.BulkEditView): form = forms.ProviderNetworkBulkEditForm +@register_model_view(ProviderNetwork, 'bulk_delete', path='delete', detail=False) class ProviderNetworkBulkDeleteView(generic.BulkDeleteView): queryset = ProviderNetwork.objects.all() filterset = filtersets.ProviderNetworkFilterSet @@ -199,6 +214,7 @@ class ProviderNetworkBulkDeleteView(generic.BulkDeleteView): # Circuit Types # +@register_model_view(CircuitType, 'list', path='', detail=False) class CircuitTypeListView(generic.ObjectListView): queryset = CircuitType.objects.annotate( circuit_count=count_related(Circuit, 'type') @@ -218,6 +234,7 @@ class CircuitTypeView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(CircuitType, 'add', detail=False) @register_model_view(CircuitType, 'edit') class CircuitTypeEditView(generic.ObjectEditView): queryset = CircuitType.objects.all() @@ -229,11 +246,13 @@ class CircuitTypeDeleteView(generic.ObjectDeleteView): queryset = CircuitType.objects.all() +@register_model_view(CircuitType, 'import', detail=False) class CircuitTypeBulkImportView(generic.BulkImportView): queryset = CircuitType.objects.all() model_form = forms.CircuitTypeImportForm +@register_model_view(CircuitType, 'bulk_edit', path='edit', detail=False) class CircuitTypeBulkEditView(generic.BulkEditView): queryset = CircuitType.objects.annotate( circuit_count=count_related(Circuit, 'type') @@ -243,6 +262,7 @@ class CircuitTypeBulkEditView(generic.BulkEditView): form = forms.CircuitTypeBulkEditForm +@register_model_view(CircuitType, 'bulk_delete', path='delete', detail=False) class CircuitTypeBulkDeleteView(generic.BulkDeleteView): queryset = CircuitType.objects.annotate( circuit_count=count_related(Circuit, 'type') @@ -255,6 +275,7 @@ class CircuitTypeBulkDeleteView(generic.BulkDeleteView): # Circuits # +@register_model_view(Circuit, 'list', path='', detail=False) class CircuitListView(generic.ObjectListView): queryset = Circuit.objects.prefetch_related( 'tenant__group', 'termination_a__termination', 'termination_z__termination', @@ -269,6 +290,7 @@ class CircuitView(generic.ObjectView): queryset = Circuit.objects.all() +@register_model_view(Circuit, 'add', detail=False) @register_model_view(Circuit, 'edit') class CircuitEditView(generic.ObjectEditView): queryset = Circuit.objects.all() @@ -280,6 +302,7 @@ class CircuitDeleteView(generic.ObjectDeleteView): queryset = Circuit.objects.all() +@register_model_view(Circuit, 'import', detail=False) class CircuitBulkImportView(generic.BulkImportView): queryset = Circuit.objects.all() model_form = forms.CircuitImportForm @@ -295,6 +318,7 @@ class CircuitBulkImportView(generic.BulkImportView): return data +@register_model_view(Circuit, 'bulk_edit', path='edit', detail=False) class CircuitBulkEditView(generic.BulkEditView): queryset = Circuit.objects.prefetch_related( 'tenant__group', 'termination_a__termination', 'termination_z__termination', @@ -304,6 +328,7 @@ class CircuitBulkEditView(generic.BulkEditView): form = forms.CircuitBulkEditForm +@register_model_view(Circuit, 'bulk_delete', path='delete', detail=False) class CircuitBulkDeleteView(generic.BulkDeleteView): queryset = Circuit.objects.prefetch_related( 'tenant__group', 'termination_a__termination', 'termination_z__termination', @@ -397,6 +422,7 @@ class CircuitContactsView(ObjectContactsView): # Circuit terminations # +@register_model_view(CircuitTermination, 'list', path='', detail=False) class CircuitTerminationListView(generic.ObjectListView): queryset = CircuitTermination.objects.all() filterset = filtersets.CircuitTerminationFilterSet @@ -409,6 +435,7 @@ class CircuitTerminationView(generic.ObjectView): queryset = CircuitTermination.objects.all() +@register_model_view(CircuitTermination, 'add', detail=False) @register_model_view(CircuitTermination, 'edit') class CircuitTerminationEditView(generic.ObjectEditView): queryset = CircuitTermination.objects.all() @@ -420,11 +447,13 @@ class CircuitTerminationDeleteView(generic.ObjectDeleteView): queryset = CircuitTermination.objects.all() +@register_model_view(CircuitTermination, 'import', detail=False) class CircuitTerminationBulkImportView(generic.BulkImportView): queryset = CircuitTermination.objects.all() model_form = forms.CircuitTerminationImportForm +@register_model_view(CircuitTermination, 'bulk_edit', path='edit', detail=False) class CircuitTerminationBulkEditView(generic.BulkEditView): queryset = CircuitTermination.objects.all() filterset = filtersets.CircuitTerminationFilterSet @@ -432,6 +461,7 @@ class CircuitTerminationBulkEditView(generic.BulkEditView): form = forms.CircuitTerminationBulkEditForm +@register_model_view(CircuitTermination, 'bulk_delete', path='delete', detail=False) class CircuitTerminationBulkDeleteView(generic.BulkDeleteView): queryset = CircuitTermination.objects.all() filterset = filtersets.CircuitTerminationFilterSet @@ -446,6 +476,7 @@ register_model_view(CircuitTermination, 'trace', kwargs={'model': CircuitTermina # Circuit Groups # +@register_model_view(CircuitGroup, 'list', path='', detail=False) class CircuitGroupListView(generic.ObjectListView): queryset = CircuitGroup.objects.annotate( circuit_group_assignment_count=count_related(CircuitGroupAssignment, 'group') @@ -465,6 +496,7 @@ class CircuitGroupView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(CircuitGroup, 'add', detail=False) @register_model_view(CircuitGroup, 'edit') class CircuitGroupEditView(generic.ObjectEditView): queryset = CircuitGroup.objects.all() @@ -476,11 +508,13 @@ class CircuitGroupDeleteView(generic.ObjectDeleteView): queryset = CircuitGroup.objects.all() +@register_model_view(CircuitGroup, 'import', detail=False) class CircuitGroupBulkImportView(generic.BulkImportView): queryset = CircuitGroup.objects.all() model_form = forms.CircuitGroupImportForm +@register_model_view(CircuitGroup, 'bulk_edit', path='edit', detail=False) class CircuitGroupBulkEditView(generic.BulkEditView): queryset = CircuitGroup.objects.all() filterset = filtersets.CircuitGroupFilterSet @@ -488,6 +522,7 @@ class CircuitGroupBulkEditView(generic.BulkEditView): form = forms.CircuitGroupBulkEditForm +@register_model_view(CircuitGroup, 'bulk_delete', path='delete', detail=False) class CircuitGroupBulkDeleteView(generic.BulkDeleteView): queryset = CircuitGroup.objects.all() filterset = filtersets.CircuitGroupFilterSet @@ -498,6 +533,7 @@ class CircuitGroupBulkDeleteView(generic.BulkDeleteView): # Circuit Groups # +@register_model_view(CircuitGroupAssignment, 'list', path='', detail=False) class CircuitGroupAssignmentListView(generic.ObjectListView): queryset = CircuitGroupAssignment.objects.all() filterset = filtersets.CircuitGroupAssignmentFilterSet @@ -510,6 +546,7 @@ class CircuitGroupAssignmentView(generic.ObjectView): queryset = CircuitGroupAssignment.objects.all() +@register_model_view(CircuitGroupAssignment, 'add', detail=False) @register_model_view(CircuitGroupAssignment, 'edit') class CircuitGroupAssignmentEditView(generic.ObjectEditView): queryset = CircuitGroupAssignment.objects.all() @@ -521,11 +558,13 @@ class CircuitGroupAssignmentDeleteView(generic.ObjectDeleteView): queryset = CircuitGroupAssignment.objects.all() +@register_model_view(CircuitGroupAssignment, 'import', detail=False) class CircuitGroupAssignmentBulkImportView(generic.BulkImportView): queryset = CircuitGroupAssignment.objects.all() model_form = forms.CircuitGroupAssignmentImportForm +@register_model_view(CircuitGroupAssignment, 'bulk_edit', path='edit', detail=False) class CircuitGroupAssignmentBulkEditView(generic.BulkEditView): queryset = CircuitGroupAssignment.objects.all() filterset = filtersets.CircuitGroupAssignmentFilterSet @@ -533,7 +572,114 @@ class CircuitGroupAssignmentBulkEditView(generic.BulkEditView): form = forms.CircuitGroupAssignmentBulkEditForm +@register_model_view(CircuitGroupAssignment, 'bulk_delete', path='delete', detail=False) class CircuitGroupAssignmentBulkDeleteView(generic.BulkDeleteView): queryset = CircuitGroupAssignment.objects.all() filterset = filtersets.CircuitGroupAssignmentFilterSet table = tables.CircuitGroupAssignmentTable + + +# +# Virtual circuits +# + +class VirtualCircuitListView(generic.ObjectListView): + queryset = VirtualCircuit.objects.annotate( + termination_count=count_related(VirtualCircuitTermination, 'virtual_circuit') + ) + filterset = filtersets.VirtualCircuitFilterSet + filterset_form = forms.VirtualCircuitFilterForm + table = tables.VirtualCircuitTable + + +@register_model_view(VirtualCircuit) +class VirtualCircuitView(generic.ObjectView): + queryset = VirtualCircuit.objects.all() + + +@register_model_view(VirtualCircuit, 'edit') +class VirtualCircuitEditView(generic.ObjectEditView): + queryset = VirtualCircuit.objects.all() + form = forms.VirtualCircuitForm + + +@register_model_view(VirtualCircuit, 'delete') +class VirtualCircuitDeleteView(generic.ObjectDeleteView): + queryset = VirtualCircuit.objects.all() + + +class VirtualCircuitBulkImportView(generic.BulkImportView): + queryset = VirtualCircuit.objects.all() + model_form = forms.VirtualCircuitImportForm + additional_permissions = [ + 'circuits.add_virtualcircuittermination', + ] + related_object_forms = { + 'terminations': forms.VirtualCircuitTerminationImportRelatedForm, + } + + def prep_related_object_data(self, parent, data): + data.update({'virtual_circuit': parent}) + return data + + +class VirtualCircuitBulkEditView(generic.BulkEditView): + queryset = VirtualCircuit.objects.annotate( + termination_count=count_related(VirtualCircuitTermination, 'virtual_circuit') + ) + filterset = filtersets.VirtualCircuitFilterSet + table = tables.VirtualCircuitTable + form = forms.VirtualCircuitBulkEditForm + + +class VirtualCircuitBulkDeleteView(generic.BulkDeleteView): + queryset = VirtualCircuit.objects.annotate( + termination_count=count_related(VirtualCircuitTermination, 'virtual_circuit') + ) + filterset = filtersets.VirtualCircuitFilterSet + table = tables.VirtualCircuitTable + + +# +# Virtual circuit terminations +# + +class VirtualCircuitTerminationListView(generic.ObjectListView): + queryset = VirtualCircuitTermination.objects.all() + filterset = filtersets.VirtualCircuitTerminationFilterSet + filterset_form = forms.VirtualCircuitTerminationFilterForm + table = tables.VirtualCircuitTerminationTable + + +@register_model_view(VirtualCircuitTermination) +class VirtualCircuitTerminationView(generic.ObjectView): + queryset = VirtualCircuitTermination.objects.all() + + +@register_model_view(VirtualCircuitTermination, 'edit') +class VirtualCircuitTerminationEditView(generic.ObjectEditView): + queryset = VirtualCircuitTermination.objects.all() + form = forms.VirtualCircuitTerminationForm + + +@register_model_view(VirtualCircuitTermination, 'delete') +class VirtualCircuitTerminationDeleteView(generic.ObjectDeleteView): + queryset = VirtualCircuitTermination.objects.all() + + +class VirtualCircuitTerminationBulkImportView(generic.BulkImportView): + queryset = VirtualCircuitTermination.objects.all() + model_form = forms.VirtualCircuitTerminationImportForm + + +class VirtualCircuitTerminationBulkEditView(generic.BulkEditView): + queryset = VirtualCircuitTermination.objects.all() + filterset = filtersets.VirtualCircuitTerminationFilterSet + table = tables.VirtualCircuitTerminationTable + form = forms.VirtualCircuitTerminationBulkEditForm + + +class VirtualCircuitTerminationBulkDeleteView(generic.BulkDeleteView): + queryset = VirtualCircuitTermination.objects.all() + filterset = filtersets.VirtualCircuitTerminationFilterSet + table = tables.VirtualCircuitTerminationTable diff --git a/netbox/core/api/schema.py b/netbox/core/api/schema.py index 1ac822b8c..fad907ac1 100644 --- a/netbox/core/api/schema.py +++ b/netbox/core/api/schema.py @@ -35,7 +35,10 @@ class ChoiceFieldFix(OpenApiSerializerFieldExtension): elif direction == "response": value = build_cf - label = {**build_basic_type(OpenApiTypes.STR), "enum": list(OrderedDict.fromkeys(self.target.choices.values()))} + label = { + **build_basic_type(OpenApiTypes.STR), + "enum": list(OrderedDict.fromkeys(self.target.choices.values())) + } return build_object_type( properties={ diff --git a/netbox/core/api/serializers_/jobs.py b/netbox/core/api/serializers_/jobs.py index 544dddb56..306287e88 100644 --- a/netbox/core/api/serializers_/jobs.py +++ b/netbox/core/api/serializers_/jobs.py @@ -22,7 +22,7 @@ class JobSerializer(BaseModelSerializer): class Meta: model = Job fields = [ - 'id', 'url', 'display_url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', 'interval', - 'started', 'completed', 'user', 'data', 'error', 'job_id', + 'id', 'url', 'display_url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', + 'interval', 'started', 'completed', 'user', 'data', 'error', 'job_id', ] brief_fields = ('url', 'created', 'completed', 'user', 'status') diff --git a/netbox/core/migrations/0001_squashed_0005.py b/netbox/core/migrations/0001_squashed_0005.py index 971370bf2..b89fa3b25 100644 --- a/netbox/core/migrations/0001_squashed_0005.py +++ b/netbox/core/migrations/0001_squashed_0005.py @@ -8,13 +8,12 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('core', '0001_initial'), ('core', '0002_managedfile'), ('core', '0003_job'), ('core', '0004_replicate_jobresults'), - ('core', '0005_job_created_auto_now') + ('core', '0005_job_created_auto_now'), ] dependencies = [ @@ -30,7 +29,10 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), ('name', models.CharField(max_length=100, unique=True)), @@ -55,9 +57,28 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(editable=False)), ('path', models.CharField(editable=False, max_length=1000)), ('size', models.PositiveIntegerField(editable=False)), - ('hash', models.CharField(editable=False, max_length=64, validators=[django.core.validators.RegexValidator(message='Length must be 64 hexadecimal characters.', regex='^[0-9a-f]{64}$')])), + ( + 'hash', + models.CharField( + editable=False, + max_length=64, + validators=[ + django.core.validators.RegexValidator( + message='Length must be 64 hexadecimal characters.', regex='^[0-9a-f]{64}$' + ) + ], + ), + ), ('data', models.BinaryField()), - ('source', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='datafiles', to='core.datasource')), + ( + 'source', + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name='datafiles', + to='core.datasource', + ), + ), ], options={ 'ordering': ('source', 'path'), @@ -76,8 +97,18 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('object_id', models.PositiveBigIntegerField()), - ('datafile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='core.datafile')), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype')), + ( + 'datafile', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='+', to='core.datafile' + ), + ), + ( + 'object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype' + ), + ), ], options={ 'indexes': [models.Index(fields=['object_type', 'object_id'], name='core_autosy_object__c17bac_idx')], @@ -97,8 +128,26 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(blank=True, editable=False, null=True)), ('file_root', models.CharField(max_length=1000)), ('file_path', models.FilePathField(editable=False)), - ('data_file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile')), - ('data_source', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource')), + ( + 'data_file', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='core.datafile', + ), + ), + ( + 'data_source', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='core.datasource', + ), + ), ('auto_sync_enabled', models.BooleanField(default=False)), ], options={ @@ -108,7 +157,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='managedfile', - constraint=models.UniqueConstraint(fields=('file_root', 'file_path'), name='core_managedfile_unique_root_path'), + constraint=models.UniqueConstraint( + fields=('file_root', 'file_path'), name='core_managedfile_unique_root_path' + ), ), migrations.CreateModel( name='Job', @@ -118,14 +169,33 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=200)), ('created', models.DateTimeField()), ('scheduled', models.DateTimeField(blank=True, null=True)), - ('interval', models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ( + 'interval', + models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), ('started', models.DateTimeField(blank=True, null=True)), ('completed', models.DateTimeField(blank=True, null=True)), ('status', models.CharField(default='pending', max_length=30)), ('data', models.JSONField(blank=True, null=True)), ('job_id', models.UUIDField(unique=True)), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='contenttypes.contenttype')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ( + 'object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='contenttypes.contenttype' + ), + ), + ( + 'user', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'ordering': ['-created'], diff --git a/netbox/core/migrations/0006_datasource_type_remove_choices.py b/netbox/core/migrations/0006_datasource_type_remove_choices.py index 0ad8d8854..7c9914298 100644 --- a/netbox/core/migrations/0006_datasource_type_remove_choices.py +++ b/netbox/core/migrations/0006_datasource_type_remove_choices.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0005_job_created_auto_now'), ] diff --git a/netbox/core/migrations/0007_job_add_error_field.py b/netbox/core/migrations/0007_job_add_error_field.py index e2e173bfd..3b0e02b56 100644 --- a/netbox/core/migrations/0007_job_add_error_field.py +++ b/netbox/core/migrations/0007_job_add_error_field.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0006_datasource_type_remove_choices'), ] diff --git a/netbox/core/migrations/0008_contenttype_proxy.py b/netbox/core/migrations/0008_contenttype_proxy.py index dee82a969..9acaf3ad7 100644 --- a/netbox/core/migrations/0008_contenttype_proxy.py +++ b/netbox/core/migrations/0008_contenttype_proxy.py @@ -3,7 +3,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('core', '0007_job_add_error_field'), @@ -12,8 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( name='ObjectType', - fields=[ - ], + fields=[], options={ 'proxy': True, 'indexes': [], diff --git a/netbox/core/migrations/0009_configrevision.py b/netbox/core/migrations/0009_configrevision.py index e7f817a16..6acd4531d 100644 --- a/netbox/core/migrations/0009_configrevision.py +++ b/netbox/core/migrations/0009_configrevision.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0008_contenttype_proxy'), ] diff --git a/netbox/core/migrations/0010_gfk_indexes.py b/netbox/core/migrations/0010_gfk_indexes.py index d51bc67ad..1e593a0c7 100644 --- a/netbox/core/migrations/0010_gfk_indexes.py +++ b/netbox/core/migrations/0010_gfk_indexes.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0009_configrevision'), ] diff --git a/netbox/core/migrations/0011_move_objectchange.py b/netbox/core/migrations/0011_move_objectchange.py index 2b41133ec..673763ce4 100644 --- a/netbox/core/migrations/0011_move_objectchange.py +++ b/netbox/core/migrations/0011_move_objectchange.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('core', '0010_gfk_indexes'), @@ -27,15 +26,49 @@ class Migration(migrations.Migration): ('object_repr', models.CharField(editable=False, max_length=200)), ('prechange_data', models.JSONField(blank=True, editable=False, null=True)), ('postchange_data', models.JSONField(blank=True, editable=False, null=True)), - ('changed_object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('related_object_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='changes', to=settings.AUTH_USER_MODEL)), + ( + 'changed_object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + 'related_object_type', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + 'user', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='changes', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'verbose_name': 'object change', 'verbose_name_plural': 'object changes', 'ordering': ['-time'], - 'indexes': [models.Index(fields=['changed_object_type', 'changed_object_id'], name='core_object_changed_c227ce_idx'), models.Index(fields=['related_object_type', 'related_object_id'], name='core_object_related_3375d6_idx')], + 'indexes': [ + models.Index( + fields=['changed_object_type', 'changed_object_id'], + name='core_object_changed_c227ce_idx', + ), + models.Index( + fields=['related_object_type', 'related_object_id'], + name='core_object_related_3375d6_idx', + ), + ], }, ), ], diff --git a/netbox/core/migrations/0012_job_object_type_optional.py b/netbox/core/migrations/0012_job_object_type_optional.py index 3c6664afc..3798b1285 100644 --- a/netbox/core/migrations/0012_job_object_type_optional.py +++ b/netbox/core/migrations/0012_job_object_type_optional.py @@ -3,7 +3,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('core', '0011_move_objectchange'), @@ -18,7 +17,7 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.CASCADE, related_name='jobs', - to='contenttypes.contenttype' + to='contenttypes.contenttype', ), ), ] diff --git a/netbox/core/models/files.py b/netbox/core/models/files.py index 7b626a441..cc446bac7 100644 --- a/netbox/core/models/files.py +++ b/netbox/core/models/files.py @@ -93,9 +93,14 @@ class ManagedFile(SyncedDataMixin, models.Model): self.file_path = os.path.basename(self.data_path) # Ensure that the file root and path make a unique pair - if self._meta.model.objects.filter(file_root=self.file_root, file_path=self.file_path).exclude(pk=self.pk).exists(): + if self._meta.model.objects.filter( + file_root=self.file_root, file_path=self.file_path + ).exclude(pk=self.pk).exists(): raise ValidationError( - f"A {self._meta.verbose_name.lower()} with this file path already exists ({self.file_root}/{self.file_path}).") + _("A {model} with this file path already exists ({path}).").format( + model=self._meta.verbose_name.lower(), + path=f"{self.file_root}/{self.file_path}" + )) def delete(self, *args, **kwargs): # Delete file from disk diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 3cfea3e2a..5caa9cc2d 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -9,6 +9,7 @@ from django.db import models from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext as _ +from rq.exceptions import InvalidJobOperation from core.choices import JobStatusChoices from core.models import ObjectType @@ -158,7 +159,11 @@ class Job(models.Model): job = queue.fetch_job(str(self.job_id)) if job: - job.cancel() + try: + job.cancel() + except InvalidJobOperation: + # Job may raise this exception from get_status() if missing from Redis + pass def start(self): """ @@ -198,7 +203,17 @@ class Job(models.Model): job_end.send(self) @classmethod - def enqueue(cls, func, instance=None, name='', user=None, schedule_at=None, interval=None, immediate=False, **kwargs): + def enqueue( + cls, + func, + instance=None, + name='', + user=None, + schedule_at=None, + interval=None, + immediate=False, + **kwargs + ): """ Create a Job instance and enqueue a job using the given callable diff --git a/netbox/core/tests/test_views.py b/netbox/core/tests/test_views.py index 3c847e4ef..047b51ef6 100644 --- a/netbox/core/tests/test_views.py +++ b/netbox/core/tests/test_views.py @@ -308,6 +308,7 @@ class BackgroundTaskTestCase(TestCase): worker = get_worker('default') job = queue.enqueue(self.dummy_job_default) worker.prepare_job_execution(job) + worker.prepare_execution(job) self.assertEqual(job.get_status(), JobStatus.STARTED) @@ -345,3 +346,32 @@ class BackgroundTaskTestCase(TestCase): self.assertIn(str(worker1.name), str(response.content)) self.assertIn('Birth', str(response.content)) self.assertIn('Total working time', str(response.content)) + + +class SystemTestCase(TestCase): + + def setUp(self): + super().setUp() + + self.user.is_staff = True + self.user.save() + + def test_system_view_default(self): + # Test UI render + response = self.client.get(reverse('core:system')) + self.assertEqual(response.status_code, 200) + + # Test export + response = self.client.get(f"{reverse('core:system')}?export=true") + self.assertEqual(response.status_code, 200) + + def test_system_view_with_config_revision(self): + ConfigRevision.objects.create() + + # Test UI render + response = self.client.get(reverse('core:system')) + self.assertEqual(response.status_code, 200) + + # Test export + response = self.client.get(f"{reverse('core:system')}?export=true") + self.assertEqual(response.status_code, 200) diff --git a/netbox/core/urls.py b/netbox/core/urls.py index fd6ec8996..b922c8bed 100644 --- a/netbox/core/urls.py +++ b/netbox/core/urls.py @@ -6,51 +6,50 @@ from . import views app_name = 'core' urlpatterns = ( - # Data sources - path('data-sources/', views.DataSourceListView.as_view(), name='datasource_list'), - path('data-sources/add/', views.DataSourceEditView.as_view(), name='datasource_add'), - path('data-sources/import/', views.DataSourceBulkImportView.as_view(), name='datasource_import'), - path('data-sources/edit/', views.DataSourceBulkEditView.as_view(), name='datasource_bulk_edit'), - path('data-sources/delete/', views.DataSourceBulkDeleteView.as_view(), name='datasource_bulk_delete'), + path('data-sources/', include(get_model_urls('core', 'datasource', detail=False))), path('data-sources//', include(get_model_urls('core', 'datasource'))), - # Data files - path('data-files/', views.DataFileListView.as_view(), name='datafile_list'), - path('data-files/delete/', views.DataFileBulkDeleteView.as_view(), name='datafile_bulk_delete'), + path('data-files/', include(get_model_urls('core', 'datafile', detail=False))), path('data-files//', include(get_model_urls('core', 'datafile'))), - # Job results - path('jobs/', views.JobListView.as_view(), name='job_list'), - path('jobs/delete/', views.JobBulkDeleteView.as_view(), name='job_bulk_delete'), - path('jobs//', views.JobView.as_view(), name='job'), - path('jobs//delete/', views.JobDeleteView.as_view(), name='job_delete'), + path('jobs/', include(get_model_urls('core', 'job', detail=False))), + path('jobs//', include(get_model_urls('core', 'job'))), - # Change logging - path('changelog/', views.ObjectChangeListView.as_view(), name='objectchange_list'), + path('changelog/', include(get_model_urls('core', 'objectchange', detail=False))), path('changelog//', include(get_model_urls('core', 'objectchange'))), # Background Tasks path('background-queues/', views.BackgroundQueueListView.as_view(), name='background_queue_list'), - path('background-queues///', views.BackgroundTaskListView.as_view(), name='background_task_list'), + path( + 'background-queues///', + views.BackgroundTaskListView.as_view(), + name='background_task_list' + ), path('background-tasks//', views.BackgroundTaskView.as_view(), name='background_task'), - path('background-tasks//delete/', views.BackgroundTaskDeleteView.as_view(), name='background_task_delete'), - path('background-tasks//requeue/', views.BackgroundTaskRequeueView.as_view(), name='background_task_requeue'), - path('background-tasks//enqueue/', views.BackgroundTaskEnqueueView.as_view(), name='background_task_enqueue'), + path( + 'background-tasks//delete/', + views.BackgroundTaskDeleteView.as_view(), + name='background_task_delete' + ), + path( + 'background-tasks//requeue/', + views.BackgroundTaskRequeueView.as_view(), + name='background_task_requeue' + ), + path( + 'background-tasks//enqueue/', + views.BackgroundTaskEnqueueView.as_view(), + name='background_task_enqueue' + ), path('background-tasks//stop/', views.BackgroundTaskStopView.as_view(), name='background_task_stop'), path('background-workers//', views.WorkerListView.as_view(), name='worker_list'), path('background-workers//', views.WorkerView.as_view(), name='worker'), - # Config revisions - path('config-revisions/', views.ConfigRevisionListView.as_view(), name='configrevision_list'), - path('config-revisions/add/', views.ConfigRevisionEditView.as_view(), name='configrevision_add'), - path('config-revisions/delete/', views.ConfigRevisionBulkDeleteView.as_view(), name='configrevision_bulk_delete'), - path('config-revisions//restore/', views.ConfigRevisionRestoreView.as_view(), name='configrevision_restore'), + path('config-revisions/', include(get_model_urls('core', 'configrevision', detail=False))), path('config-revisions//', include(get_model_urls('core', 'configrevision'))), - # System path('system/', views.SystemView.as_view(), name='system'), - # Plugins path('plugins/', views.PluginListView.as_view(), name='plugin_list'), path('plugins//', views.PluginView.as_view(), name='plugin'), ) diff --git a/netbox/core/views.py b/netbox/core/views.py index 0c6fa54c0..03ab098f5 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -43,6 +43,7 @@ from .tables import CatalogPluginTable, PluginVersionTable # Data sources # +@register_model_view(DataSource, 'list', path='', detail=False) class DataSourceListView(generic.ObjectListView): queryset = DataSource.objects.annotate( file_count=count_related(DataFile, 'source') @@ -89,6 +90,7 @@ class DataSourceSyncView(BaseObjectView): return redirect(datasource.get_absolute_url()) +@register_model_view(DataSource, 'add', detail=False) @register_model_view(DataSource, 'edit') class DataSourceEditView(generic.ObjectEditView): queryset = DataSource.objects.all() @@ -100,11 +102,13 @@ class DataSourceDeleteView(generic.ObjectDeleteView): queryset = DataSource.objects.all() +@register_model_view(DataSource, 'import', detail=False) class DataSourceBulkImportView(generic.BulkImportView): queryset = DataSource.objects.all() model_form = forms.DataSourceImportForm +@register_model_view(DataSource, 'bulk_edit', path='edit', detail=False) class DataSourceBulkEditView(generic.BulkEditView): queryset = DataSource.objects.annotate( count_files=count_related(DataFile, 'source') @@ -114,6 +118,7 @@ class DataSourceBulkEditView(generic.BulkEditView): form = forms.DataSourceBulkEditForm +@register_model_view(DataSource, 'bulk_delete', path='delete', detail=False) class DataSourceBulkDeleteView(generic.BulkDeleteView): queryset = DataSource.objects.annotate( count_files=count_related(DataFile, 'source') @@ -126,6 +131,7 @@ class DataSourceBulkDeleteView(generic.BulkDeleteView): # Data files # +@register_model_view(DataFile, 'list', path='', detail=False) class DataFileListView(generic.ObjectListView): queryset = DataFile.objects.defer('data') filterset = filtersets.DataFileFilterSet @@ -146,6 +152,7 @@ class DataFileDeleteView(generic.ObjectDeleteView): queryset = DataFile.objects.all() +@register_model_view(DataFile, 'bulk_delete', path='delete', detail=False) class DataFileBulkDeleteView(generic.BulkDeleteView): queryset = DataFile.objects.defer('data') filterset = filtersets.DataFileFilterSet @@ -156,6 +163,7 @@ class DataFileBulkDeleteView(generic.BulkDeleteView): # Jobs # +@register_model_view(Job, 'list', path='', detail=False) class JobListView(generic.ObjectListView): queryset = Job.objects.all() filterset = filtersets.JobFilterSet @@ -167,14 +175,17 @@ class JobListView(generic.ObjectListView): } +@register_model_view(Job) class JobView(generic.ObjectView): queryset = Job.objects.all() +@register_model_view(Job, 'delete') class JobDeleteView(generic.ObjectDeleteView): queryset = Job.objects.all() +@register_model_view(Job, 'bulk_delete', path='delete', detail=False) class JobBulkDeleteView(generic.BulkDeleteView): queryset = Job.objects.all() filterset = filtersets.JobFilterSet @@ -185,6 +196,7 @@ class JobBulkDeleteView(generic.BulkDeleteView): # Change logging # +@register_model_view(ObjectChange, 'list', path='', detail=False) class ObjectChangeListView(generic.ObjectListView): queryset = ObjectChange.objects.valid_models() filterset = filtersets.ObjectChangeFilterSet @@ -254,6 +266,7 @@ class ObjectChangeView(generic.ObjectView): # Config Revisions # +@register_model_view(ConfigRevision, 'list', path='', detail=False) class ConfigRevisionListView(generic.ObjectListView): queryset = ConfigRevision.objects.all() filterset = filtersets.ConfigRevisionFilterSet @@ -266,6 +279,7 @@ class ConfigRevisionView(generic.ObjectView): queryset = ConfigRevision.objects.all() +@register_model_view(ConfigRevision, 'add', detail=False) class ConfigRevisionEditView(generic.ObjectEditView): queryset = ConfigRevision.objects.all() form = forms.ConfigRevisionForm @@ -276,12 +290,14 @@ class ConfigRevisionDeleteView(generic.ObjectDeleteView): queryset = ConfigRevision.objects.all() +@register_model_view(ConfigRevision, 'bulk_delete', path='delete', detail=False) class ConfigRevisionBulkDeleteView(generic.BulkDeleteView): queryset = ConfigRevision.objects.all() filterset = filtersets.ConfigRevisionFilterSet table = tables.ConfigRevisionTable +@register_model_view(ConfigRevision, 'restore') class ConfigRevisionRestoreView(ContentTypePermissionRequiredMixin, View): def get_required_permission(self): @@ -536,11 +552,7 @@ class SystemView(UserPassesTestMixin, View): } # Configuration - try: - config = ConfigRevision.objects.get(pk=cache.get('config_version')) - except ConfigRevision.DoesNotExist: - # Fall back to using the active config data if no record is found - config = get_config() + config = get_config() # Raw data export if 'export' in request.GET: diff --git a/netbox/dcim/api/serializers_/device_components.py b/netbox/dcim/api/serializers_/device_components.py index 57111c2af..a6767bb6f 100644 --- a/netbox/dcim/api/serializers_/device_components.py +++ b/netbox/dcim/api/serializers_/device_components.py @@ -21,7 +21,7 @@ from wireless.choices import * from wireless.models import WirelessLAN from .base import ConnectedEndpointsSerializer from .cables import CabledObjectSerializer -from .devices import DeviceSerializer, ModuleSerializer, VirtualDeviceContextSerializer +from .devices import DeviceSerializer, MACAddressSerializer, ModuleSerializer, VirtualDeviceContextSerializer from .manufacturers import ManufacturerSerializer from .nested import NestedInterfaceSerializer from .roles import InventoryItemRoleSerializer @@ -210,24 +210,23 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect ) count_ipaddresses = serializers.IntegerField(read_only=True) count_fhrp_groups = serializers.IntegerField(read_only=True) - mac_address = serializers.CharField( - required=False, - default=None, - allow_blank=True, - allow_null=True - ) + # Maintains backward compatibility with NetBox [ge,xe]-0/0/[0-9]). The token {module}, if present, will be " + "automatically replaced with the position value when creating a new module." + ) + class ConsolePortTemplateForm(ModularComponentTemplateForm): fieldsets = ( @@ -992,7 +1010,8 @@ class InterfaceTemplateForm(ModularComponentTemplateForm): class Meta: model = InterfaceTemplate fields = [ - 'device_type', 'module_type', 'name', 'label', 'type', 'mgmt_only', 'enabled', 'description', 'poe_mode', 'poe_type', 'bridge', 'rf_role', + 'device_type', 'module_type', 'name', 'label', 'type', 'mgmt_only', 'enabled', 'description', 'poe_mode', + 'poe_type', 'bridge', 'rf_role', ] @@ -1174,7 +1193,10 @@ class InventoryItemTemplateForm(ComponentTemplateForm): break elif component_type and component_id: # When adding the InventoryItem from a component page - if content_type := ContentType.objects.filter(MODULAR_COMPONENT_TEMPLATE_MODELS).filter(pk=component_type).first(): + content_type = ContentType.objects.filter( + MODULAR_COMPONENT_TEMPLATE_MODELS + ).filter(pk=component_type).first() + if content_type: if component := content_type.model_class().objects.filter(pk=component_id).first(): initial[content_type.model] = component @@ -1286,16 +1308,16 @@ class PowerOutletForm(ModularDeviceComponentForm): fieldsets = ( FieldSet( - 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', 'description', - 'tags', + 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', + 'description', 'tags', ), ) class Meta: model = PowerOutlet fields = [ - 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', 'description', - 'tags', + 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', + 'description', 'tags', ] @@ -1403,7 +1425,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): FieldSet( 'device', 'module', 'name', 'label', 'type', 'speed', 'duplex', 'description', 'tags', name=_('Interface') ), - FieldSet('vrf', 'mac_address', 'wwn', name=_('Addressing')), + FieldSet('vrf', 'primary_mac_address', 'wwn', name=_('Addressing')), FieldSet('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected', name=_('Operation')), FieldSet('parent', 'bridge', 'lag', name=_('Related Interfaces')), FieldSet('poe_mode', 'poe_type', name=_('PoE')), @@ -1420,10 +1442,11 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): class Meta: model = Interface fields = [ - 'device', 'module', 'vdcs', 'name', 'label', 'type', 'speed', 'duplex', 'enabled', 'parent', 'bridge', 'lag', - 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode', + 'device', 'module', 'vdcs', 'name', 'label', 'type', 'speed', 'duplex', 'enabled', 'parent', 'bridge', + 'lag', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans', - 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'vlan_translation_policy', 'vrf', 'tags', + 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'vlan_translation_policy', 'vrf', 'primary_mac_address', + 'tags', ] widgets = { 'speed': NumberWithOptions( @@ -1595,7 +1618,10 @@ class InventoryItemForm(DeviceComponentForm): ) fieldsets = ( - FieldSet('device', 'parent', 'name', 'label', 'status', 'role', 'description', 'tags', name=_('Inventory Item')), + FieldSet( + 'device', 'parent', 'name', 'label', 'status', 'role', 'description', 'tags', + name=_('Inventory Item') + ), FieldSet('manufacturer', 'part_id', 'serial', 'asset_tag', name=_('Hardware')), FieldSet( TabbedGroups( @@ -1717,3 +1743,72 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm): 'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'comments', 'tags' ] + + +# +# Addressing +# + +class MACAddressForm(NetBoxModelForm): + mac_address = forms.CharField( + required=True, + label=_('MAC address') + ) + interface = DynamicModelChoiceField( + label=_('Interface'), + queryset=Interface.objects.all(), + required=False, + ) + vminterface = DynamicModelChoiceField( + label=_('VM Interface'), + queryset=VMInterface.objects.all(), + required=False, + ) + + fieldsets = ( + FieldSet( + 'mac_address', 'description', 'tags', + ), + FieldSet( + TabbedGroups( + FieldSet('interface', name=_('Device')), + FieldSet('vminterface', name=_('Virtual Machine')), + ), + ), + ) + + class Meta: + model = MACAddress + fields = [ + 'mac_address', 'interface', 'vminterface', 'description', 'tags', + ] + + def __init__(self, *args, **kwargs): + + # Initialize helper selectors + instance = kwargs.get('instance') + initial = kwargs.get('initial', {}).copy() + if instance: + if type(instance.assigned_object) is Interface: + initial['interface'] = instance.assigned_object + elif type(instance.assigned_object) is VMInterface: + initial['vminterface'] = instance.assigned_object + kwargs['initial'] = initial + + super().__init__(*args, **kwargs) + + def clean(self): + super().clean() + + # Handle object assignment + selected_objects = [ + field for field in ('interface', 'vminterface') if self.cleaned_data[field] + ] + if len(selected_objects) > 1: + raise forms.ValidationError({ + selected_objects[1]: _("A MAC address can only be assigned to a single object.") + }) + elif selected_objects: + self.instance.assigned_object = self.cleaned_data[selected_objects[0]] + else: + self.instance.assigned_object = None diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index d18c7ed14..6f6cd8f7c 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -243,14 +243,6 @@ class InterfaceCreateForm(ComponentCreateForm, model_forms.InterfaceForm): class Meta(model_forms.InterfaceForm.Meta): exclude = ('name', 'label') - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if 'module' in self.fields: - self.fields['name'].help_text += _( - "The string {module} will be replaced with the position of the assigned module, if any." - ) - class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): device = DynamicModelChoiceField( @@ -424,7 +416,8 @@ class VirtualChassisCreateForm(NetBoxModelForm): class Meta: model = VirtualChassis fields = [ - 'name', 'domain', 'description', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'tags', + 'name', 'domain', 'description', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', + 'tags', ] def clean(self): diff --git a/netbox/dcim/forms/object_import.py b/netbox/dcim/forms/object_import.py index d46ef83ad..821f91402 100644 --- a/netbox/dcim/forms/object_import.py +++ b/netbox/dcim/forms/object_import.py @@ -136,7 +136,8 @@ class FrontPortTemplateImportForm(forms.ModelForm): class Meta: model = FrontPortTemplate fields = [ - 'device_type', 'module_type', 'name', 'type', 'color', 'rear_port', 'rear_port_position', 'label', 'description', + 'device_type', 'module_type', 'name', 'type', 'color', 'rear_port', 'rear_port_position', 'label', + 'description', ] diff --git a/netbox/dcim/graphql/filters.py b/netbox/dcim/graphql/filters.py index 8c256aecb..94f2c6d38 100644 --- a/netbox/dcim/graphql/filters.py +++ b/netbox/dcim/graphql/filters.py @@ -23,6 +23,7 @@ __all__ = ( 'InventoryItemFilter', 'InventoryItemRoleFilter', 'LocationFilter', + 'MACAddressFilter', 'ManufacturerFilter', 'ModuleFilter', 'ModuleBayFilter', @@ -133,6 +134,12 @@ class FrontPortTemplateFilter(BaseFilterMixin): pass +@strawberry_django.filter(models.MACAddress, lookups=True) +@autotype_decorator(filtersets.MACAddressFilterSet) +class MACAddressFilter(BaseFilterMixin): + pass + + @strawberry_django.filter(models.Interface, lookups=True) @autotype_decorator(filtersets.InterfaceFilterSet) class InterfaceFilter(BaseFilterMixin): diff --git a/netbox/dcim/graphql/schema.py b/netbox/dcim/graphql/schema.py index 65818fb20..011a2b58b 100644 --- a/netbox/dcim/graphql/schema.py +++ b/netbox/dcim/graphql/schema.py @@ -44,6 +44,9 @@ class DCIMQuery: front_port_template: FrontPortTemplateType = strawberry_django.field() front_port_template_list: List[FrontPortTemplateType] = strawberry_django.field() + mac_address: MACAddressType = strawberry_django.field() + mac_address_list: List[MACAddressType] = strawberry_django.field() + interface: InterfaceType = strawberry_django.field() interface_list: List[InterfaceType] = strawberry_django.field() diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index cc1bcac0f..1020861f4 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -34,6 +34,7 @@ __all__ = ( 'InventoryItemRoleType', 'InventoryItemTemplateType', 'LocationType', + 'MACAddressType', 'ManufacturerType', 'ModularComponentType', 'ModuleType', @@ -366,6 +367,22 @@ class FrontPortTemplateType(ModularComponentTemplateType): rear_port: Annotated["RearPortTemplateType", strawberry.lazy('dcim.graphql.types')] +@strawberry_django.type( + models.MACAddress, + exclude=('assigned_object_type', 'assigned_object_id'), + filters=MACAddressFilter +) +class MACAddressType(NetBoxObjectType): + mac_address: str + + @strawberry_django.field + def assigned_object(self) -> Annotated[Union[ + Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], + Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')], + ], strawberry.union("MACAddressAssignmentType")] | None: + return self.assigned_object + + @strawberry_django.type( models.Interface, exclude=('_path',), @@ -373,7 +390,6 @@ class FrontPortTemplateType(ModularComponentTemplateType): ) class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin): _name: str - mac_address: str | None wwn: str | None parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None @@ -381,6 +397,7 @@ class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, P wireless_link: Annotated["WirelessLinkType", strawberry.lazy('wireless.graphql.types')] | None untagged_vlan: Annotated["VLANType", strawberry.lazy('ipam.graphql.types')] | None vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None + primary_mac_address: Annotated["MACAddressType", strawberry.lazy('dcim.graphql.types')] | None qinq_svlan: Annotated["VLANType", strawberry.lazy('ipam.graphql.types')] | None vlan_translation_policy: Annotated["VLANTranslationPolicyType", strawberry.lazy('ipam.graphql.types')] | None @@ -390,6 +407,7 @@ class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, P wireless_lans: List[Annotated["WirelessLANType", strawberry.lazy('wireless.graphql.types')]] member_interfaces: List[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]] child_interfaces: List[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]] + mac_addresses: List[Annotated["MACAddressType", strawberry.lazy('dcim.graphql.types')]] @strawberry_django.type( @@ -464,7 +482,9 @@ class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, Organi return self.cluster_set.all() @strawberry_django.field - def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: + def circuit_terminations(self) -> List[ + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] + ]: return self.circuit_terminations.all() @@ -710,7 +730,9 @@ class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): return self.cluster_set.all() @strawberry_django.field - def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: + def circuit_terminations(self) -> List[ + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] + ]: return self.circuit_terminations.all() @@ -742,7 +764,9 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje return self.cluster_set.all() @strawberry_django.field - def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: + def circuit_terminations(self) -> List[ + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] + ]: return self.circuit_terminations.all() @@ -766,7 +790,9 @@ class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): return self.cluster_set.all() @strawberry_django.field - def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: + def circuit_terminations(self) -> List[ + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] + ]: return self.circuit_terminations.all() diff --git a/netbox/dcim/migrations/0001_squashed.py b/netbox/dcim/migrations/0001_squashed.py index cf0ef4816..f08fe1d70 100644 --- a/netbox/dcim/migrations/0001_squashed.py +++ b/netbox/dcim/migrations/0001_squashed.py @@ -13,11 +13,9 @@ import utilities.validators class Migration(migrations.Migration): - initial = True - dependencies = [ - ] + dependencies = [] replaces = [ ('dcim', '0001_initial'), @@ -64,7 +62,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), @@ -83,7 +86,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(blank=True, max_length=50)), @@ -100,7 +108,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), @@ -119,7 +132,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(blank=True, max_length=50)), @@ -137,14 +155,34 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(primary_key=True, serialize=False)), ('local_context_data', models.JSONField(blank=True, null=True)), ('name', models.CharField(blank=True, max_length=64, null=True)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize, null=True)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize, null=True + ), + ), ('serial', models.CharField(blank=True, max_length=50)), ('asset_tag', models.CharField(blank=True, max_length=50, null=True, unique=True)), - ('position', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ( + 'position', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), ('face', models.CharField(blank=True, max_length=50)), ('status', models.CharField(default='active', max_length=50)), - ('vc_position', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(255)])), - ('vc_priority', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(255)])), + ( + 'vc_position', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MaxValueValidator(255)] + ), + ), + ( + 'vc_priority', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MaxValueValidator(255)] + ), + ), ('comments', models.TextField(blank=True)), ], options={ @@ -159,7 +197,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ], @@ -174,7 +217,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ], @@ -228,13 +276,27 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), ('mark_connected', models.BooleanField(default=False)), ('type', models.CharField(max_length=50)), - ('rear_port_position', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(1024)])), + ( + 'rear_port_position', + models.PositiveSmallIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(1024), + ], + ), + ), ], options={ 'ordering': ('device', '_name'), @@ -247,11 +309,25 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(max_length=50)), - ('rear_port_position', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(1024)])), + ( + 'rear_port_position', + models.PositiveSmallIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(1024), + ], + ), + ), ], options={ 'ordering': ('device_type', '_name'), @@ -271,9 +347,24 @@ class Migration(migrations.Migration): ('mark_connected', models.BooleanField(default=False)), ('enabled', models.BooleanField(default=True)), ('mac_address', dcim.fields.MACAddressField(blank=True, null=True)), - ('mtu', models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(65536)])), + ( + 'mtu', + models.PositiveIntegerField( + blank=True, + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(65536), + ], + ), + ), ('mode', models.CharField(blank=True, max_length=50)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize_interface)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize_interface + ), + ), ('type', models.CharField(max_length=50)), ('mgmt_only', models.BooleanField(default=False)), ], @@ -290,7 +381,12 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=64)), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize_interface)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize_interface + ), + ), ('type', models.CharField(max_length=50)), ('mgmt_only', models.BooleanField(default=False)), ], @@ -306,7 +402,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('part_id', models.CharField(blank=True, max_length=50)), @@ -388,8 +489,19 @@ class Migration(migrations.Migration): ('supply', models.CharField(default='ac', max_length=50)), ('phase', models.CharField(default='single-phase', max_length=50)), ('voltage', models.SmallIntegerField(validators=[utilities.validators.ExclusionValidator([0])])), - ('amperage', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1)])), - ('max_utilization', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)])), + ( + 'amperage', + models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1)]), + ), + ( + 'max_utilization', + models.PositiveSmallIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ] + ), + ), ('available_power', models.PositiveIntegerField(default=0, editable=False)), ('comments', models.TextField(blank=True)), ], @@ -405,7 +517,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), @@ -424,7 +541,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(blank=True, max_length=50)), @@ -455,14 +577,29 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), ('mark_connected', models.BooleanField(default=False)), ('type', models.CharField(blank=True, max_length=50)), - ('maximum_draw', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), - ('allocated_draw', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ( + 'maximum_draw', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), + ( + 'allocated_draw', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), ], options={ 'ordering': ('device', '_name'), @@ -475,12 +612,27 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(blank=True, max_length=50)), - ('maximum_draw', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), - ('allocated_draw', models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ( + 'maximum_draw', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), + ( + 'allocated_draw', + models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), + ), ], options={ 'ordering': ('device_type', '_name'), @@ -494,14 +646,28 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=100)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('facility_id', models.CharField(blank=True, max_length=50, null=True)), ('status', models.CharField(default='active', max_length=50)), ('serial', models.CharField(blank=True, max_length=50)), ('asset_tag', models.CharField(blank=True, max_length=50, null=True, unique=True)), ('type', models.CharField(blank=True, max_length=50)), ('width', models.PositiveSmallIntegerField(default=19)), - ('u_height', models.PositiveSmallIntegerField(default=42, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)])), + ( + 'u_height', + models.PositiveSmallIntegerField( + default=42, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + ), + ), ('desc_units', models.BooleanField(default=False)), ('outer_width', models.PositiveSmallIntegerField(blank=True, null=True)), ('outer_depth', models.PositiveSmallIntegerField(blank=True, null=True)), @@ -519,7 +685,10 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('units', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveSmallIntegerField(), size=None)), + ( + 'units', + django.contrib.postgres.fields.ArrayField(base_field=models.PositiveSmallIntegerField(), size=None), + ), ('description', models.CharField(max_length=200)), ], options={ @@ -550,13 +719,27 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)), ('mark_connected', models.BooleanField(default=False)), ('type', models.CharField(max_length=50)), - ('positions', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(1024)])), + ( + 'positions', + models.PositiveSmallIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(1024), + ], + ), + ), ], options={ 'ordering': ('device', '_name'), @@ -569,11 +752,25 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('type', models.CharField(max_length=50)), - ('positions', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(1024)])), + ( + 'positions', + models.PositiveSmallIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(1024), + ], + ), + ), ], options={ 'ordering': ('device_type', '_name'), @@ -606,7 +803,12 @@ class Migration(migrations.Migration): ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=100, unique=True)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('slug', models.SlugField(max_length=100, unique=True)), ('status', models.CharField(default='active', max_length=50)), ('facility', models.CharField(blank=True, max_length=50)), @@ -654,7 +856,16 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), ('domain', models.CharField(blank=True, max_length=30)), - ('master', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vc_master_for', to='dcim.device')), + ( + 'master', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vc_master_for', + to='dcim.device', + ), + ), ], options={ 'verbose_name_plural': 'virtual chassis', diff --git a/netbox/dcim/migrations/0002_squashed.py b/netbox/dcim/migrations/0002_squashed.py index 786167680..2e830560f 100644 --- a/netbox/dcim/migrations/0002_squashed.py +++ b/netbox/dcim/migrations/0002_squashed.py @@ -6,7 +6,6 @@ import taggit.managers class Migration(migrations.Migration): - dependencies = [ ('dcim', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), @@ -28,17 +27,35 @@ class Migration(migrations.Migration): migrations.AddField( model_name='sitegroup', name='parent', - field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dcim.sitegroup'), + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='dcim.sitegroup', + ), ), migrations.AddField( model_name='site', name='group', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sites', to='dcim.sitegroup'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='sites', + to='dcim.sitegroup', + ), ), migrations.AddField( model_name='site', name='region', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sites', to='dcim.region'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='sites', + to='dcim.region', + ), ), migrations.AddField( model_name='site', @@ -48,32 +65,56 @@ class Migration(migrations.Migration): migrations.AddField( model_name='site', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sites', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='sites', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='region', name='parent', - field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dcim.region'), + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='dcim.region', + ), ), migrations.AddField( model_name='rearporttemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='rearport', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='rearport', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='rearport', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='rearport', @@ -83,7 +124,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='rackreservation', name='rack', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='dcim.rack'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='dcim.rack' + ), ), migrations.AddField( model_name='rackreservation', @@ -93,7 +136,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='rackreservation', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='rackreservations', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='rackreservations', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='rackreservation', @@ -103,12 +152,24 @@ class Migration(migrations.Migration): migrations.AddField( model_name='rack', name='location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='racks', to='dcim.location'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='racks', + to='dcim.location', + ), ), migrations.AddField( model_name='rack', name='role', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='racks', to='dcim.rackrole'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='racks', + to='dcim.rackrole', + ), ), migrations.AddField( model_name='rack', @@ -123,32 +184,52 @@ class Migration(migrations.Migration): migrations.AddField( model_name='rack', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='racks', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='racks', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='powerporttemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='powerport', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='powerport', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='powerport', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='powerport', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='powerport', @@ -158,7 +239,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='powerpanel', name='location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dcim.location'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dcim.location' + ), ), migrations.AddField( model_name='powerpanel', @@ -173,37 +256,63 @@ class Migration(migrations.Migration): migrations.AddField( model_name='poweroutlettemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='poweroutlettemplate', name='power_port', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='poweroutlet_templates', to='dcim.powerporttemplate'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='poweroutlet_templates', + to='dcim.powerporttemplate', + ), ), migrations.AddField( model_name='poweroutlet', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='poweroutlet', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='poweroutlet', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='poweroutlet', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='poweroutlet', name='power_port', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='poweroutlets', to='dcim.powerport'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='poweroutlets', + to='dcim.powerport', + ), ), migrations.AddField( model_name='poweroutlet', @@ -213,27 +322,45 @@ class Migration(migrations.Migration): migrations.AddField( model_name='powerfeed', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='powerfeed', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='powerfeed', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='powerfeed', name='power_panel', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='powerfeeds', to='dcim.powerpanel'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='powerfeeds', to='dcim.powerpanel' + ), ), migrations.AddField( model_name='powerfeed', name='rack', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='powerfeeds', to='dcim.rack'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='powerfeeds', + to='dcim.rack', + ), ), migrations.AddField( model_name='powerfeed', @@ -243,32 +370,60 @@ class Migration(migrations.Migration): migrations.AddField( model_name='platform', name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='platforms', to='dcim.manufacturer'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='platforms', + to='dcim.manufacturer', + ), ), migrations.AddField( model_name='location', name='parent', - field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dcim.location'), + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='dcim.location', + ), ), migrations.AddField( model_name='location', name='site', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='locations', to='dcim.site'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='locations', to='dcim.site' + ), ), migrations.AddField( model_name='inventoryitem', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='inventoryitem', name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_items', to='dcim.manufacturer'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='inventory_items', + to='dcim.manufacturer', + ), ), migrations.AddField( model_name='inventoryitem', name='parent', - field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_items', to='dcim.inventoryitem'), + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='child_items', + to='dcim.inventoryitem', + ), ), migrations.AddField( model_name='inventoryitem', @@ -278,36 +433,62 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interfacetemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='interface', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='interface', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='interface', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='interface', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='interface', name='lag', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_interfaces', to='dcim.interface'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='member_interfaces', + to='dcim.interface', + ), ), migrations.AddField( model_name='interface', name='parent', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='child_interfaces', to='dcim.interface'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='child_interfaces', + to='dcim.interface', + ), ), ] diff --git a/netbox/dcim/migrations/0003_squashed_0130.py b/netbox/dcim/migrations/0003_squashed_0130.py index 592aaf9a8..0248d9ba1 100644 --- a/netbox/dcim/migrations/0003_squashed_0130.py +++ b/netbox/dcim/migrations/0003_squashed_0130.py @@ -4,7 +4,6 @@ import taggit.managers class Migration(migrations.Migration): - dependencies = [ ('dcim', '0002_auto_20160622_1821'), ('virtualization', '0001_virtualization'), @@ -160,37 +159,61 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='untagged_vlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interfaces_as_untagged', to='ipam.vlan'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='interfaces_as_untagged', + to='ipam.vlan', + ), ), migrations.AddField( model_name='frontporttemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='frontporttemplate', name='rear_port', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='frontport_templates', to='dcim.rearporttemplate'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='frontport_templates', + to='dcim.rearporttemplate', + ), ), migrations.AddField( model_name='frontport', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='frontport', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='frontport', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='frontport', name='rear_port', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='frontports', to='dcim.rearport'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='frontports', to='dcim.rearport' + ), ), migrations.AddField( model_name='frontport', @@ -200,7 +223,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='devicetype', name='manufacturer', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='device_types', to='dcim.manufacturer'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='device_types', to='dcim.manufacturer' + ), ), migrations.AddField( model_name='devicetype', @@ -210,17 +235,27 @@ class Migration(migrations.Migration): migrations.AddField( model_name='devicebaytemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='devicebay', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='devicebay', name='installed_device', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parent_bay', to='dcim.device'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='parent_bay', + to='dcim.device', + ), ), migrations.AddField( model_name='devicebay', @@ -230,47 +265,89 @@ class Migration(migrations.Migration): migrations.AddField( model_name='device', name='cluster', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='devices', to='virtualization.cluster'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='devices', + to='virtualization.cluster', + ), ), migrations.AddField( model_name='device', name='device_role', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.devicerole'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.devicerole' + ), ), migrations.AddField( model_name='device', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='instances', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='instances', to='dcim.devicetype' + ), ), migrations.AddField( model_name='device', name='location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.location'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='devices', + to='dcim.location', + ), ), migrations.AddField( model_name='device', name='platform', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='devices', to='dcim.platform'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='devices', + to='dcim.platform', + ), ), migrations.AddField( model_name='device', name='primary_ip4', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='primary_ip4_for', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='primary_ip4_for', + to='ipam.ipaddress', + ), ), migrations.AddField( model_name='device', name='primary_ip6', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='primary_ip6_for', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='primary_ip6_for', + to='ipam.ipaddress', + ), ), migrations.AddField( model_name='device', name='rack', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.rack'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='devices', + to='dcim.rack', + ), ), migrations.AddField( model_name='device', name='site', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.site'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='dcim.site' + ), ), migrations.AddField( model_name='device', @@ -280,37 +357,63 @@ class Migration(migrations.Migration): migrations.AddField( model_name='device', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='devices', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='device', name='virtual_chassis', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='dcim.virtualchassis'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='members', + to='dcim.virtualchassis', + ), ), migrations.AddField( model_name='consoleserverporttemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='consoleserverport', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='consoleserverport', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='consoleserverport', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='consoleserverport', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='consoleserverport', @@ -320,27 +423,41 @@ class Migration(migrations.Migration): migrations.AddField( model_name='consoleporttemplate', name='device_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), ), migrations.AddField( model_name='consoleport', name='_cable_peer_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='consoleport', name='_path', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dcim.cablepath' + ), ), migrations.AddField( model_name='consoleport', name='cable', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.cable' + ), ), migrations.AddField( model_name='consoleport', name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), ), migrations.AddField( model_name='consoleport', @@ -350,22 +467,34 @@ class Migration(migrations.Migration): migrations.AddField( model_name='cablepath', name='destination_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='cablepath', name='origin_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype' + ), ), migrations.AddField( model_name='cable', name='_termination_a_device', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device' + ), ), migrations.AddField( model_name='cable', name='_termination_b_device', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device' + ), ), migrations.AddField( model_name='cable', @@ -375,12 +504,64 @@ class Migration(migrations.Migration): migrations.AddField( model_name='cable', name='termination_a_type', - field=models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'powerfeed', 'poweroutlet', 'powerport', 'rearport'))), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), + models.Q( + ('app_label', 'dcim'), + ( + 'model__in', + ( + 'consoleport', + 'consoleserverport', + 'frontport', + 'interface', + 'powerfeed', + 'poweroutlet', + 'powerport', + 'rearport', + ), + ), + ), + _connector='OR', + ) + ), + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='cable', name='termination_b_type', - field=models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'powerfeed', 'poweroutlet', 'powerport', 'rearport'))), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), + models.Q( + ('app_label', 'dcim'), + ( + 'model__in', + ( + 'consoleport', + 'consoleserverport', + 'frontport', + 'interface', + 'powerfeed', + 'poweroutlet', + 'powerport', + 'rearport', + ), + ), + ), + _connector='OR', + ) + ), + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AlterUniqueTogether( name='rearporttemplate', @@ -456,7 +637,11 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='device', - unique_together={('rack', 'position', 'face'), ('virtual_chassis', 'vc_position'), ('site', 'tenant', 'name')}, + unique_together={ + ('rack', 'position', 'face'), + ('virtual_chassis', 'vc_position'), + ('site', 'tenant', 'name'), + }, ), migrations.AlterUniqueTogether( name='consoleserverporttemplate', diff --git a/netbox/dcim/migrations/0131_squashed_0159.py b/netbox/dcim/migrations/0131_squashed_0159.py index f7e7cfdb2..3866e8cc8 100644 --- a/netbox/dcim/migrations/0131_squashed_0159.py +++ b/netbox/dcim/migrations/0131_squashed_0159.py @@ -10,7 +10,6 @@ import utilities.ordering class Migration(migrations.Migration): - replaces = [ ('dcim', '0131_consoleport_speed'), ('dcim', '0132_cable_length'), @@ -40,7 +39,7 @@ class Migration(migrations.Migration): ('dcim', '0156_location_status'), ('dcim', '0157_new_cabling_models'), ('dcim', '0158_populate_cable_terminations'), - ('dcim', '0159_populate_cable_paths') + ('dcim', '0159_populate_cable_paths'), ] dependencies = [ @@ -96,17 +95,35 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='bridge', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bridge_interfaces', to='dcim.interface'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='bridge_interfaces', + to='dcim.interface', + ), ), migrations.AddField( model_name='location', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='locations', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='locations', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='cable', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='cables', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='cables', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='devicetype', @@ -148,7 +165,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='location', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('site', 'name'), name='dcim_location_name'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('site', 'name'), name='dcim_location_name' + ), ), migrations.AddConstraint( model_name='location', @@ -156,7 +175,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='location', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('site', 'slug'), name='dcim_location_slug'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('site', 'slug'), name='dcim_location_slug' + ), ), migrations.AddConstraint( model_name='region', @@ -164,7 +185,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='region', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('name',), name='dcim_region_name'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('name',), name='dcim_region_name' + ), ), migrations.AddConstraint( model_name='region', @@ -172,7 +195,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='region', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('slug',), name='dcim_region_slug'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('slug',), name='dcim_region_slug' + ), ), migrations.AddConstraint( model_name='sitegroup', @@ -180,7 +205,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='sitegroup', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('name',), name='dcim_sitegroup_name'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('name',), name='dcim_sitegroup_name' + ), ), migrations.AddConstraint( model_name='sitegroup', @@ -188,7 +215,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='sitegroup', - constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('slug',), name='dcim_sitegroup_slug'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent', None)), fields=('slug',), name='dcim_sitegroup_slug' + ), ), migrations.AddField( model_name='devicerole', @@ -328,7 +357,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='tx_power', - field=models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(127)]), + field=models.PositiveSmallIntegerField( + blank=True, null=True, validators=[django.core.validators.MaxValueValidator(127)] + ), ), migrations.AddField( model_name='interface', @@ -338,7 +369,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='wireless_link', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wireless.wirelesslink'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='wireless.wirelesslink', + ), ), migrations.AddField( model_name='site', @@ -348,12 +385,24 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='device', name='primary_ip4', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='ipam.ipaddress', + ), ), migrations.AlterField( model_name='device', name='primary_ip6', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='ipam.ipaddress', + ), ), migrations.RemoveField( model_name='site', @@ -372,7 +421,23 @@ class Migration(migrations.Migration): name='contact_phone', ), migrations.RunSQL( - sql="\n DO $$\n DECLARE\n idx record;\n BEGIN\n FOR idx IN\n SELECT indexname AS old_name,\n replace(indexname, 'module', 'inventoryitem') AS new_name\n FROM pg_indexes\n WHERE schemaname = 'public' AND\n tablename = 'dcim_inventoryitem' AND\n indexname LIKE 'dcim_module_%'\n LOOP\n EXECUTE format(\n 'ALTER INDEX %I RENAME TO %I;',\n idx.old_name,\n idx.new_name\n );\n END LOOP;\n END$$;\n ", + sql="""DO $$ + DECLARE idx record; + BEGIN + FOR idx IN + SELECT indexname AS old_name, replace(indexname, 'module', 'inventoryitem') AS new_name + FROM pg_indexes + WHERE schemaname = 'public' AND + tablename = 'dcim_inventoryitem' AND + indexname LIKE 'dcim_module_%' + LOOP + EXECUTE format( + 'ALTER INDEX %I RENAME TO %I;', + idx.old_name, + idx.new_name + ); + END LOOP; + END$$;""", ), migrations.AlterModelOptions( name='consoleporttemplate', @@ -405,49 +470,99 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='consoleporttemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='consoleserverporttemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='frontporttemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='interfacetemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='poweroutlettemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='powerporttemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AlterField( model_name='rearporttemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.CreateModel( name='ModuleType', fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('model', models.CharField(max_length=100)), ('part_number', models.CharField(blank=True, max_length=50)), ('comments', models.TextField(blank=True)), - ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='module_types', to='dcim.manufacturer')), + ( + 'manufacturer', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='module_types', to='dcim.manufacturer' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -460,14 +575,27 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('position', models.CharField(blank=True, max_length=30)), ('description', models.CharField(blank=True, max_length=200)), - ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device')), + ( + 'device', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -480,15 +608,35 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('local_context_data', models.JSONField(blank=True, null=True)), ('serial', models.CharField(blank=True, max_length=50)), ('asset_tag', models.CharField(blank=True, max_length=50, null=True, unique=True)), ('comments', models.TextField(blank=True)), - ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modules', to='dcim.device')), - ('module_bay', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='installed_module', to='dcim.modulebay')), - ('module_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='instances', to='dcim.moduletype')), + ( + 'device', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='modules', to='dcim.device' + ), + ), + ( + 'module_bay', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name='installed_module', + to='dcim.modulebay', + ), + ), + ( + 'module_type', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='instances', to='dcim.moduletype' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -498,72 +646,156 @@ class Migration(migrations.Migration): migrations.AddField( model_name='consoleport', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='consoleporttemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='consoleserverport', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='consoleserverporttemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='frontport', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='frontporttemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='interface', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='interfacetemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='poweroutlet', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='poweroutlettemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='powerport', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='powerporttemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AddField( model_name='rearport', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='rearporttemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AlterUniqueTogether( name='consoleporttemplate', @@ -598,7 +830,10 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=100, unique=True)), ('slug', models.SlugField(max_length=100, unique=True)), @@ -613,7 +848,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='inventoryitem', name='role', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_items', to='dcim.inventoryitemrole'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='inventory_items', + to='dcim.inventoryitemrole', + ), ), migrations.AddField( model_name='inventoryitem', @@ -623,12 +864,39 @@ class Migration(migrations.Migration): migrations.AddField( model_name='inventoryitem', name='component_type', - field=models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'poweroutlet', 'powerport', 'rearport'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + ('app_label', 'dcim'), + ( + 'model__in', + ( + 'consoleport', + 'consoleserverport', + 'frontport', + 'interface', + 'poweroutlet', + 'powerport', + 'rearport', + ), + ), + ), + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='interface', name='vrf', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interfaces', to='ipam.vrf'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='interfaces', + to='ipam.vrf', + ), ), migrations.AddField( model_name='interface', @@ -952,7 +1220,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('description', models.CharField(blank=True, max_length=200)), ('component_id', models.PositiveBigIntegerField(blank=True, null=True)), @@ -961,11 +1234,67 @@ class Migration(migrations.Migration): ('rght', models.PositiveIntegerField(editable=False)), ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), ('level', models.PositiveIntegerField(editable=False)), - ('component_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ('consoleporttemplate', 'consoleserverporttemplate', 'frontporttemplate', 'interfacetemplate', 'poweroutlettemplate', 'powerporttemplate', 'rearporttemplate'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')), - ('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.manufacturer')), - ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_items', to='dcim.inventoryitemtemplate')), - ('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.inventoryitemrole')), + ( + 'component_type', + models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + ('app_label', 'dcim'), + ( + 'model__in', + ( + 'consoleporttemplate', + 'consoleserverporttemplate', + 'frontporttemplate', + 'interfacetemplate', + 'poweroutlettemplate', + 'powerporttemplate', + 'rearporttemplate', + ), + ), + ), + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + 'device_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), + ), + ( + 'manufacturer', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='inventory_item_templates', + to='dcim.manufacturer', + ), + ), + ( + 'parent', + mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='child_items', + to='dcim.inventoryitemtemplate', + ), + ), + ( + 'role', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='inventory_item_templates', + to='dcim.inventoryitemrole', + ), + ), ], options={ 'ordering': ('device_type__id', 'parent__id', '_name'), @@ -989,11 +1318,21 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=64)), - ('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)), + ( + '_name', + utilities.fields.NaturalOrderingField( + 'name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize + ), + ), ('label', models.CharField(blank=True, max_length=64)), ('position', models.CharField(blank=True, max_length=30)), ('description', models.CharField(blank=True, max_length=200)), - ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')), + ( + 'device_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype' + ), + ), ], options={ 'ordering': ('device_type', '_name'), @@ -1088,7 +1427,16 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='device', name='position', - field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100.5)]), + field=models.DecimalField( + blank=True, + decimal_places=1, + max_digits=4, + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100.5), + ], + ), ), migrations.AddField( model_name='interface', @@ -1121,12 +1469,66 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('cable_end', models.CharField(max_length=1)), ('termination_id', models.PositiveBigIntegerField()), - ('cable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='dcim.cable')), - ('termination_type', models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'powerfeed', 'poweroutlet', 'powerport', 'rearport'))), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.device')), - ('_rack', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.rack')), - ('_location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location')), - ('_site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site')), + ( + 'cable', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='dcim.cable' + ), + ), + ( + 'termination_type', + models.ForeignKey( + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), + models.Q( + ('app_label', 'dcim'), + ( + 'model__in', + ( + 'consoleport', + 'consoleserverport', + 'frontport', + 'interface', + 'powerfeed', + 'poweroutlet', + 'powerport', + 'rearport', + ), + ), + ), + _connector='OR', + ) + ), + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + '_device', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.device' + ), + ), + ( + '_rack', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.rack' + ), + ), + ( + '_location', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location' + ), + ), + ( + '_site', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site' + ), + ), ], options={ 'ordering': ('cable', 'cable_end', 'pk'), @@ -1134,7 +1536,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='cabletermination', - constraint=models.UniqueConstraint(fields=('termination_type', 'termination_id'), name='dcim_cable_termination_unique_termination'), + constraint=models.UniqueConstraint( + fields=('termination_type', 'termination_id'), name='dcim_cable_termination_unique_termination' + ), ), migrations.RenameField( model_name='cablepath', diff --git a/netbox/dcim/migrations/0160_squashed_0166.py b/netbox/dcim/migrations/0160_squashed_0166.py index 440a8115e..0deb58bab 100644 --- a/netbox/dcim/migrations/0160_squashed_0166.py +++ b/netbox/dcim/migrations/0160_squashed_0166.py @@ -6,7 +6,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('dcim', '0160_populate_cable_ends'), ('dcim', '0161_cabling_cleanup'), @@ -14,7 +13,7 @@ class Migration(migrations.Migration): ('dcim', '0163_weight_fields'), ('dcim', '0164_rack_mounting_depth'), ('dcim', '0165_standardize_description_comments'), - ('dcim', '0166_virtualdevicecontext') + ('dcim', '0166_virtualdevicecontext'), ] dependencies = [ @@ -275,7 +274,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='cabletermination', - constraint=models.UniqueConstraint(fields=('termination_type', 'termination_id'), name='dcim_cabletermination_unique_termination'), + constraint=models.UniqueConstraint( + fields=('termination_type', 'termination_id'), name='dcim_cabletermination_unique_termination' + ), ), migrations.AddConstraint( model_name='consoleport', @@ -283,39 +284,64 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='consoleporttemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_consoleporttemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_consoleporttemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='consoleporttemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_consoleporttemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_consoleporttemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='consoleserverport', - constraint=models.UniqueConstraint(fields=('device', 'name'), name='dcim_consoleserverport_unique_device_name'), + constraint=models.UniqueConstraint( + fields=('device', 'name'), name='dcim_consoleserverport_unique_device_name' + ), ), migrations.AddConstraint( model_name='consoleserverporttemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_consoleserverporttemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_consoleserverporttemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='consoleserverporttemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_consoleserverporttemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_consoleserverporttemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='device', - constraint=models.UniqueConstraint(django.db.models.functions.text.Lower('name'), models.F('site'), models.F('tenant'), name='dcim_device_unique_name_site_tenant'), + constraint=models.UniqueConstraint( + django.db.models.functions.text.Lower('name'), + models.F('site'), + models.F('tenant'), + name='dcim_device_unique_name_site_tenant', + ), ), migrations.AddConstraint( model_name='device', - constraint=models.UniqueConstraint(django.db.models.functions.text.Lower('name'), models.F('site'), condition=models.Q(('tenant__isnull', True)), name='dcim_device_unique_name_site', violation_error_message='Device name must be unique per site.'), + constraint=models.UniqueConstraint( + django.db.models.functions.text.Lower('name'), + models.F('site'), + condition=models.Q(('tenant__isnull', True)), + name='dcim_device_unique_name_site', + violation_error_message='Device name must be unique per site.', + ), ), migrations.AddConstraint( model_name='device', - constraint=models.UniqueConstraint(fields=('rack', 'position', 'face'), name='dcim_device_unique_rack_position_face'), + constraint=models.UniqueConstraint( + fields=('rack', 'position', 'face'), name='dcim_device_unique_rack_position_face' + ), ), migrations.AddConstraint( model_name='device', - constraint=models.UniqueConstraint(fields=('virtual_chassis', 'vc_position'), name='dcim_device_unique_virtual_chassis_vc_position'), + constraint=models.UniqueConstraint( + fields=('virtual_chassis', 'vc_position'), name='dcim_device_unique_virtual_chassis_vc_position' + ), ), migrations.AddConstraint( model_name='devicebay', @@ -323,15 +349,21 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='devicebaytemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_devicebaytemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_devicebaytemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='devicetype', - constraint=models.UniqueConstraint(fields=('manufacturer', 'model'), name='dcim_devicetype_unique_manufacturer_model'), + constraint=models.UniqueConstraint( + fields=('manufacturer', 'model'), name='dcim_devicetype_unique_manufacturer_model' + ), ), migrations.AddConstraint( model_name='devicetype', - constraint=models.UniqueConstraint(fields=('manufacturer', 'slug'), name='dcim_devicetype_unique_manufacturer_slug'), + constraint=models.UniqueConstraint( + fields=('manufacturer', 'slug'), name='dcim_devicetype_unique_manufacturer_slug' + ), ), migrations.AddConstraint( model_name='frontport', @@ -339,19 +371,27 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='frontport', - constraint=models.UniqueConstraint(fields=('rear_port', 'rear_port_position'), name='dcim_frontport_unique_rear_port_position'), + constraint=models.UniqueConstraint( + fields=('rear_port', 'rear_port_position'), name='dcim_frontport_unique_rear_port_position' + ), ), migrations.AddConstraint( model_name='frontporttemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_frontporttemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_frontporttemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='frontporttemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_frontporttemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_frontporttemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='frontporttemplate', - constraint=models.UniqueConstraint(fields=('rear_port', 'rear_port_position'), name='dcim_frontporttemplate_unique_rear_port_position'), + constraint=models.UniqueConstraint( + fields=('rear_port', 'rear_port_position'), name='dcim_frontporttemplate_unique_rear_port_position' + ), ), migrations.AddConstraint( model_name='interface', @@ -359,27 +399,46 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='interfacetemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_interfacetemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_interfacetemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='interfacetemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_interfacetemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_interfacetemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='inventoryitem', - constraint=models.UniqueConstraint(fields=('device', 'parent', 'name'), name='dcim_inventoryitem_unique_device_parent_name'), + constraint=models.UniqueConstraint( + fields=('device', 'parent', 'name'), name='dcim_inventoryitem_unique_device_parent_name' + ), ), migrations.AddConstraint( model_name='inventoryitemtemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'parent', 'name'), name='dcim_inventoryitemtemplate_unique_device_type_parent_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'parent', 'name'), + name='dcim_inventoryitemtemplate_unique_device_type_parent_name', + ), ), migrations.AddConstraint( model_name='location', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('site', 'name'), name='dcim_location_name', violation_error_message='A location with this name already exists within the specified site.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('site', 'name'), + name='dcim_location_name', + violation_error_message='A location with this name already exists within the specified site.', + ), ), migrations.AddConstraint( model_name='location', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('site', 'slug'), name='dcim_location_slug', violation_error_message='A location with this slug already exists within the specified site.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('site', 'slug'), + name='dcim_location_slug', + violation_error_message='A location with this slug already exists within the specified site.', + ), ), migrations.AddConstraint( model_name='modulebay', @@ -387,15 +446,21 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='modulebaytemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_modulebaytemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_modulebaytemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='moduletype', - constraint=models.UniqueConstraint(fields=('manufacturer', 'model'), name='dcim_moduletype_unique_manufacturer_model'), + constraint=models.UniqueConstraint( + fields=('manufacturer', 'model'), name='dcim_moduletype_unique_manufacturer_model' + ), ), migrations.AddConstraint( model_name='powerfeed', - constraint=models.UniqueConstraint(fields=('power_panel', 'name'), name='dcim_powerfeed_unique_power_panel_name'), + constraint=models.UniqueConstraint( + fields=('power_panel', 'name'), name='dcim_powerfeed_unique_power_panel_name' + ), ), migrations.AddConstraint( model_name='poweroutlet', @@ -403,11 +468,15 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='poweroutlettemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_poweroutlettemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_poweroutlettemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='poweroutlettemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_poweroutlettemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_poweroutlettemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='powerpanel', @@ -419,11 +488,15 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='powerporttemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_powerporttemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_powerporttemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='powerporttemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_powerporttemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_powerporttemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='rack', @@ -431,7 +504,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='rack', - constraint=models.UniqueConstraint(fields=('location', 'facility_id'), name='dcim_rack_unique_location_facility_id'), + constraint=models.UniqueConstraint( + fields=('location', 'facility_id'), name='dcim_rack_unique_location_facility_id' + ), ), migrations.AddConstraint( model_name='rearport', @@ -439,27 +514,51 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='rearporttemplate', - constraint=models.UniqueConstraint(fields=('device_type', 'name'), name='dcim_rearporttemplate_unique_device_type_name'), + constraint=models.UniqueConstraint( + fields=('device_type', 'name'), name='dcim_rearporttemplate_unique_device_type_name' + ), ), migrations.AddConstraint( model_name='rearporttemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_rearporttemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_rearporttemplate_unique_module_type_name' + ), ), migrations.AddConstraint( model_name='region', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('name',), name='dcim_region_name', violation_error_message='A top-level region with this name already exists.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('name',), + name='dcim_region_name', + violation_error_message='A top-level region with this name already exists.', + ), ), migrations.AddConstraint( model_name='region', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('slug',), name='dcim_region_slug', violation_error_message='A top-level region with this slug already exists.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('slug',), + name='dcim_region_slug', + violation_error_message='A top-level region with this slug already exists.', + ), ), migrations.AddConstraint( model_name='sitegroup', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('name',), name='dcim_sitegroup_name', violation_error_message='A top-level site group with this name already exists.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('name',), + name='dcim_sitegroup_name', + violation_error_message='A top-level site group with this name already exists.', + ), ), migrations.AddConstraint( model_name='sitegroup', - constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('slug',), name='dcim_sitegroup_slug', violation_error_message='A top-level site group with this slug already exists.'), + constraint=models.UniqueConstraint( + condition=models.Q(('parent__isnull', True)), + fields=('slug',), + name='dcim_sitegroup_slug', + violation_error_message='A top-level site group with this slug already exists.', + ), ), migrations.AddField( model_name='devicetype', @@ -592,17 +691,56 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('name', models.CharField(max_length=64)), ('status', models.CharField(max_length=50)), ('identifier', models.PositiveSmallIntegerField(blank=True, null=True)), ('comments', models.TextField(blank=True)), - ('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='dcim.device')), - ('primary_ip4', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')), - ('primary_ip6', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')), + ( + 'device', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vdcs', + to='dcim.device', + ), + ), + ( + 'primary_ip4', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='ipam.ipaddress', + ), + ), + ( + 'primary_ip6', + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='ipam.ipaddress', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vdcs', + to='tenancy.tenant', + ), + ), ], options={ 'ordering': ['name'], @@ -615,7 +753,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='virtualdevicecontext', - constraint=models.UniqueConstraint(fields=('device', 'identifier'), name='dcim_virtualdevicecontext_device_identifier'), + constraint=models.UniqueConstraint( + fields=('device', 'identifier'), name='dcim_virtualdevicecontext_device_identifier' + ), ), migrations.AddConstraint( model_name='virtualdevicecontext', diff --git a/netbox/dcim/migrations/0167_squashed_0182.py b/netbox/dcim/migrations/0167_squashed_0182.py index 735cb3efa..d0ad5379f 100644 --- a/netbox/dcim/migrations/0167_squashed_0182.py +++ b/netbox/dcim/migrations/0167_squashed_0182.py @@ -6,7 +6,6 @@ import utilities.fields class Migration(migrations.Migration): - replaces = [ ('dcim', '0167_module_status'), ('dcim', '0168_interface_template_enabled'), @@ -24,7 +23,7 @@ class Migration(migrations.Migration): ('dcim', '0179_interfacetemplate_rf_role'), ('dcim', '0180_powerfeed_tenant'), ('dcim', '0181_rename_device_role_device_role'), - ('dcim', '0182_zero_length_cable_fix') + ('dcim', '0182_zero_length_cable_fix'), ] dependencies = [ @@ -48,27 +47,57 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interfacetemplate', name='bridge', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bridge_interfaces', to='dcim.interfacetemplate'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='bridge_interfaces', + to='dcim.interfacetemplate', + ), ), migrations.AddField( model_name='devicetype', name='default_platform', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.platform'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='dcim.platform', + ), ), migrations.AddField( model_name='device', name='config_template', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='extras.configtemplate'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)ss', + to='extras.configtemplate', + ), ), migrations.AddField( model_name='devicerole', name='config_template', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='device_roles', to='extras.configtemplate'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='device_roles', + to='extras.configtemplate', + ), ), migrations.AddField( model_name='platform', name='config_template', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='platforms', to='extras.configtemplate'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='platforms', + to='extras.configtemplate', + ), ), migrations.AddField( model_name='cabletermination', @@ -83,22 +112,30 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='powerport', name='allocated_draw', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]), + field=models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), ), migrations.AlterField( model_name='powerport', name='maximum_draw', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]), + field=models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), ), migrations.AlterField( model_name='powerporttemplate', name='allocated_draw', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]), + field=models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), ), migrations.AlterField( model_name='powerporttemplate', name='maximum_draw', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]), + field=models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), ), migrations.RemoveField( model_name='platform', @@ -126,112 +163,160 @@ class Migration(migrations.Migration): migrations.AddField( model_name='device', name='oob_ip', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='ipam.ipaddress', + ), ), migrations.AddField( model_name='device', name='console_port_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ConsolePort'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.ConsolePort' + ), ), migrations.AddField( model_name='device', name='console_server_port_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ConsoleServerPort'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.ConsoleServerPort' + ), ), migrations.AddField( model_name='device', name='power_port_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.PowerPort'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.PowerPort' + ), ), migrations.AddField( model_name='device', name='power_outlet_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.PowerOutlet'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.PowerOutlet' + ), ), migrations.AddField( model_name='device', name='interface_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.Interface'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.Interface' + ), ), migrations.AddField( model_name='device', name='front_port_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.FrontPort'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.FrontPort' + ), ), migrations.AddField( model_name='device', name='rear_port_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.RearPort'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.RearPort' + ), ), migrations.AddField( model_name='device', name='device_bay_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.DeviceBay'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.DeviceBay' + ), ), migrations.AddField( model_name='device', name='module_bay_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ModuleBay'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.ModuleBay' + ), ), migrations.AddField( model_name='device', name='inventory_item_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.InventoryItem'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device', to_model='dcim.InventoryItem' + ), ), migrations.AddField( model_name='devicetype', name='console_port_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ConsolePortTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.ConsolePortTemplate' + ), ), migrations.AddField( model_name='devicetype', name='console_server_port_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ConsoleServerPortTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.ConsoleServerPortTemplate' + ), ), migrations.AddField( model_name='devicetype', name='power_port_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.PowerPortTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.PowerPortTemplate' + ), ), migrations.AddField( model_name='devicetype', name='power_outlet_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.PowerOutletTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.PowerOutletTemplate' + ), ), migrations.AddField( model_name='devicetype', name='interface_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.InterfaceTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.InterfaceTemplate' + ), ), migrations.AddField( model_name='devicetype', name='front_port_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.FrontPortTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.FrontPortTemplate' + ), ), migrations.AddField( model_name='devicetype', name='rear_port_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.RearPortTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.RearPortTemplate' + ), ), migrations.AddField( model_name='devicetype', name='device_bay_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.DeviceBayTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.DeviceBayTemplate' + ), ), migrations.AddField( model_name='devicetype', name='module_bay_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ModuleBayTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.ModuleBayTemplate' + ), ), migrations.AddField( model_name='devicetype', name='inventory_item_template_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.InventoryItemTemplate'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='device_type', to_model='dcim.InventoryItemTemplate' + ), ), migrations.AddField( model_name='virtualchassis', name='member_count', - field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='virtual_chassis', to_model='dcim.Device'), + field=utilities.fields.CounterCacheField( + default=0, editable=False, to_field='virtual_chassis', to_model='dcim.Device' + ), ), migrations.AddField( model_name='interfacetemplate', @@ -241,7 +326,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='powerfeed', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='power_feeds', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='power_feeds', + to='tenancy.tenant', + ), ), migrations.RenameField( model_name='device', diff --git a/netbox/dcim/migrations/0184_protect_child_interfaces.py b/netbox/dcim/migrations/0184_protect_child_interfaces.py index 3459e23fc..58eca506d 100644 --- a/netbox/dcim/migrations/0184_protect_child_interfaces.py +++ b/netbox/dcim/migrations/0184_protect_child_interfaces.py @@ -5,7 +5,6 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ ('dcim', '0183_devicetype_exclude_from_utilization'), ] @@ -14,6 +13,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='interface', name='parent', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='child_interfaces', to='dcim.interface'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.RESTRICT, + related_name='child_interfaces', + to='dcim.interface', + ), ), ] diff --git a/netbox/dcim/migrations/0185_gfk_indexes.py b/netbox/dcim/migrations/0185_gfk_indexes.py index 84cdc53ff..5c099b380 100644 --- a/netbox/dcim/migrations/0185_gfk_indexes.py +++ b/netbox/dcim/migrations/0185_gfk_indexes.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0184_protect_child_interfaces'), ] diff --git a/netbox/dcim/migrations/0186_location_facility.py b/netbox/dcim/migrations/0186_location_facility.py index 759ee813b..3d22503b6 100644 --- a/netbox/dcim/migrations/0186_location_facility.py +++ b/netbox/dcim/migrations/0186_location_facility.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0185_gfk_indexes'), ] diff --git a/netbox/dcim/migrations/0187_alter_device_vc_position.py b/netbox/dcim/migrations/0187_alter_device_vc_position.py index d4a42dc20..10b636959 100644 --- a/netbox/dcim/migrations/0187_alter_device_vc_position.py +++ b/netbox/dcim/migrations/0187_alter_device_vc_position.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0186_location_facility'), ] diff --git a/netbox/dcim/migrations/0188_racktype.py b/netbox/dcim/migrations/0188_racktype.py index aa45246e5..a5265d030 100644 --- a/netbox/dcim/migrations/0188_racktype.py +++ b/netbox/dcim/migrations/0188_racktype.py @@ -9,7 +9,6 @@ import utilities.ordering class Migration(migrations.Migration): - dependencies = [ ('extras', '0118_customfield_uniqueness'), ('dcim', '0187_alter_device_vc_position'), @@ -22,36 +21,41 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField( - blank=True, - default=dict, - encoder=utilities.json.CustomFieldJSONEncoder - )), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), ('weight', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True)), ('weight_unit', models.CharField(blank=True, max_length=50)), ('_abs_weight', models.PositiveBigIntegerField(blank=True, null=True)), - ('manufacturer', models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name='rack_types', - to='dcim.manufacturer' - )), + ( + 'manufacturer', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='rack_types', to='dcim.manufacturer' + ), + ), ('model', models.CharField(max_length=100)), ('slug', models.SlugField(max_length=100, unique=True)), ('form_factor', models.CharField(max_length=50)), ('width', models.PositiveSmallIntegerField(default=19)), - ('u_height', models.PositiveSmallIntegerField( - default=42, - validators=[ - django.core.validators.MinValueValidator(1), - django.core.validators.MaxValueValidator(100), - ] - )), - ('starting_unit', models.PositiveSmallIntegerField( - default=1, - validators=[django.core.validators.MinValueValidator(1)] - )), + ( + 'u_height', + models.PositiveSmallIntegerField( + default=42, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + ), + ), + ( + 'starting_unit', + models.PositiveSmallIntegerField( + default=1, validators=[django.core.validators.MinValueValidator(1)] + ), + ), ('desc_units', models.BooleanField(default=False)), ('outer_width', models.PositiveSmallIntegerField(blank=True, null=True)), ('outer_depth', models.PositiveSmallIntegerField(blank=True, null=True)), diff --git a/netbox/dcim/migrations/0189_moduletype_rack_airflow.py b/netbox/dcim/migrations/0189_moduletype_rack_airflow.py index 31787b67d..c356e32f7 100644 --- a/netbox/dcim/migrations/0189_moduletype_rack_airflow.py +++ b/netbox/dcim/migrations/0189_moduletype_rack_airflow.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0188_racktype'), ] diff --git a/netbox/dcim/migrations/0190_nested_modules.py b/netbox/dcim/migrations/0190_nested_modules.py index 9cef40efb..239e08639 100644 --- a/netbox/dcim/migrations/0190_nested_modules.py +++ b/netbox/dcim/migrations/0190_nested_modules.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0189_moduletype_rack_airflow'), ('extras', '0121_customfield_related_object_filter'), @@ -34,12 +33,25 @@ class Migration(migrations.Migration): migrations.AddField( model_name='modulebay', name='module', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.module', + ), ), migrations.AddField( model_name='modulebay', name='parent', - field=mptt.fields.TreeForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dcim.modulebay'), + field=mptt.fields.TreeForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='dcim.modulebay', + ), ), migrations.AddField( model_name='modulebay', @@ -56,19 +68,35 @@ class Migration(migrations.Migration): migrations.AddField( model_name='modulebaytemplate', name='module_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.moduletype', + ), ), migrations.AlterField( model_name='modulebaytemplate', name='device_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='%(class)ss', + to='dcim.devicetype', + ), ), migrations.AddConstraint( model_name='modulebay', - constraint=models.UniqueConstraint(fields=('device', 'module', 'name'), name='dcim_modulebay_unique_device_module_name'), + constraint=models.UniqueConstraint( + fields=('device', 'module', 'name'), name='dcim_modulebay_unique_device_module_name' + ), ), migrations.AddConstraint( model_name='modulebaytemplate', - constraint=models.UniqueConstraint(fields=('module_type', 'name'), name='dcim_modulebaytemplate_unique_module_type_name'), + constraint=models.UniqueConstraint( + fields=('module_type', 'name'), name='dcim_modulebaytemplate_unique_module_type_name' + ), ), ] diff --git a/netbox/dcim/migrations/0191_module_bay_rebuild.py b/netbox/dcim/migrations/0191_module_bay_rebuild.py index 260063213..4f8a461f2 100644 --- a/netbox/dcim/migrations/0191_module_bay_rebuild.py +++ b/netbox/dcim/migrations/0191_module_bay_rebuild.py @@ -13,14 +13,10 @@ def rebuild_mptt(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('dcim', '0190_nested_modules'), ] operations = [ - migrations.RunPython( - code=rebuild_mptt, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=rebuild_mptt, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/dcim/migrations/0192_inventoryitem_status.py b/netbox/dcim/migrations/0192_inventoryitem_status.py index 335ab2ca7..027f2daef 100644 --- a/netbox/dcim/migrations/0192_inventoryitem_status.py +++ b/netbox/dcim/migrations/0192_inventoryitem_status.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0191_module_bay_rebuild'), ] diff --git a/netbox/dcim/migrations/0193_poweroutlet_color.py b/netbox/dcim/migrations/0193_poweroutlet_color.py index 0a6c08b48..f7e3c430c 100644 --- a/netbox/dcim/migrations/0193_poweroutlet_color.py +++ b/netbox/dcim/migrations/0193_poweroutlet_color.py @@ -5,7 +5,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('dcim', '0192_inventoryitem_status'), ] diff --git a/netbox/dcim/migrations/0194_charfield_null_choices.py b/netbox/dcim/migrations/0194_charfield_null_choices.py index 8e507c050..83c056386 100644 --- a/netbox/dcim/migrations/0194_charfield_null_choices.py +++ b/netbox/dcim/migrations/0194_charfield_null_choices.py @@ -69,7 +69,6 @@ def set_null_values(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('dcim', '0193_poweroutlet_color'), ] @@ -280,8 +279,5 @@ class Migration(migrations.Migration): name='cable_end', field=models.CharField(blank=True, max_length=1, null=True), ), - migrations.RunPython( - code=set_null_values, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_null_values, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/dcim/migrations/0195_interface_vlan_translation_policy.py b/netbox/dcim/migrations/0195_interface_vlan_translation_policy.py index 42ff1205a..9ec404886 100644 --- a/netbox/dcim/migrations/0195_interface_vlan_translation_policy.py +++ b/netbox/dcim/migrations/0195_interface_vlan_translation_policy.py @@ -5,7 +5,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0194_charfield_null_choices'), ('ipam', '0074_vlantranslationpolicy_vlantranslationrule'), @@ -15,6 +14,8 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='vlan_translation_policy', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ipam.vlantranslationpolicy'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ipam.vlantranslationpolicy' + ), ), ] diff --git a/netbox/dcim/migrations/0196_qinq_svlan.py b/netbox/dcim/migrations/0196_qinq_svlan.py index 9012d74f3..a03ad144a 100644 --- a/netbox/dcim/migrations/0196_qinq_svlan.py +++ b/netbox/dcim/migrations/0196_qinq_svlan.py @@ -3,7 +3,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0195_interface_vlan_translation_policy'), ('ipam', '0075_vlan_qinq'), @@ -13,7 +12,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='interface', name='qinq_svlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)ss_svlan', to='ipam.vlan'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='%(class)ss_svlan', + to='ipam.vlan', + ), ), migrations.AlterField( model_name='interface', @@ -23,6 +28,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='interface', name='untagged_vlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)ss_as_untagged', to='ipam.vlan'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='%(class)ss_as_untagged', + to='ipam.vlan', + ), ), ] diff --git a/netbox/dcim/migrations/0197_natural_sort_collation.py b/netbox/dcim/migrations/0197_natural_sort_collation.py index a77632b37..268bda7eb 100644 --- a/netbox/dcim/migrations/0197_natural_sort_collation.py +++ b/netbox/dcim/migrations/0197_natural_sort_collation.py @@ -3,15 +3,14 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('dcim', '0196_qinq_svlan'), ] operations = [ CreateCollation( - "natural_sort", - provider="icu", - locale="und-u-kn-true", + 'natural_sort', + provider='icu', + locale='und-u-kn-true', ), ] diff --git a/netbox/dcim/migrations/0198_natural_ordering.py b/netbox/dcim/migrations/0198_natural_ordering.py index 83e94a195..cf4361a2b 100644 --- a/netbox/dcim/migrations/0198_natural_ordering.py +++ b/netbox/dcim/migrations/0198_natural_ordering.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0197_natural_sort_collation'), ] diff --git a/netbox/dcim/migrations/0199_macaddress.py b/netbox/dcim/migrations/0199_macaddress.py new file mode 100644 index 000000000..ae18d5f63 --- /dev/null +++ b/netbox/dcim/migrations/0199_macaddress.py @@ -0,0 +1,51 @@ +import django.db.models.deletion +import taggit.managers +from django.db import migrations, models + +import dcim.fields +import utilities.json + + +class Migration(migrations.Migration): + dependencies = [ + ('dcim', '0198_natural_ordering'), + ('extras', '0122_charfield_null_choices'), + ] + + operations = [ + migrations.CreateModel( + name='MACAddress', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), + ('description', models.CharField(blank=True, max_length=200)), + ('comments', models.TextField(blank=True)), + ('mac_address', dcim.fields.MACAddressField()), + ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)), + ( + 'assigned_object_type', + models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'dcim'), ('model', 'interface')), + models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), + _connector='OR', + ) + ), + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={'abstract': False, 'ordering': ('mac_address',)}, + ), + ] diff --git a/netbox/dcim/migrations/0200_populate_mac_addresses.py b/netbox/dcim/migrations/0200_populate_mac_addresses.py new file mode 100644 index 000000000..0cd18d78e --- /dev/null +++ b/netbox/dcim/migrations/0200_populate_mac_addresses.py @@ -0,0 +1,46 @@ +import django.db.models.deletion +from django.db import migrations, models + + +def populate_mac_addresses(apps, schema_editor): + ContentType = apps.get_model('contenttypes', 'ContentType') + Interface = apps.get_model('dcim', 'Interface') + MACAddress = apps.get_model('dcim', 'MACAddress') + interface_ct = ContentType.objects.get_for_model(Interface) + + mac_addresses = [ + MACAddress( + mac_address=interface.mac_address, assigned_object_type=interface_ct, assigned_object_id=interface.pk + ) + for interface in Interface.objects.filter(mac_address__isnull=False) + ] + MACAddress.objects.bulk_create(mac_addresses, batch_size=100) + + # TODO: Optimize interface updates + for mac_address in mac_addresses: + Interface.objects.filter(pk=mac_address.assigned_object_id).update(primary_mac_address=mac_address) + + +class Migration(migrations.Migration): + dependencies = [ + ('dcim', '0199_macaddress'), + ] + + operations = [ + migrations.AddField( + model_name='interface', + name='primary_mac_address', + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='dcim.macaddress', + ), + ), + migrations.RunPython(code=populate_mac_addresses, reverse_code=migrations.RunPython.noop), + migrations.RemoveField( + model_name='interface', + name='mac_address', + ), + ] diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index ddd4d2426..b4f057711 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -311,7 +311,9 @@ class PowerPortTemplate(ModularComponentTemplateModel): if self.maximum_draw is not None and self.allocated_draw is not None: if self.allocated_draw > self.maximum_draw: raise ValidationError({ - 'allocated_draw': _("Allocated draw cannot exceed the maximum draw ({maximum_draw}W).").format(maximum_draw=self.maximum_draw) + 'allocated_draw': _( + "Allocated draw cannot exceed the maximum draw ({maximum_draw}W)." + ).format(maximum_draw=self.maximum_draw) }) def to_yaml(self): @@ -365,11 +367,15 @@ class PowerOutletTemplate(ModularComponentTemplateModel): if self.power_port: if self.device_type and self.power_port.device_type != self.device_type: raise ValidationError( - _("Parent power port ({power_port}) must belong to the same device type").format(power_port=self.power_port) + _("Parent power port ({power_port}) must belong to the same device type").format( + power_port=self.power_port + ) ) if self.module_type and self.power_port.module_type != self.module_type: raise ValidationError( - _("Parent power port ({power_port}) must belong to the same module type").format(power_port=self.power_port) + _("Parent power port ({power_port}) must belong to the same module type").format( + power_port=self.power_port + ) ) def instantiate(self, **kwargs): @@ -467,11 +473,15 @@ class InterfaceTemplate(ModularComponentTemplateModel): raise ValidationError({'bridge': _("An interface cannot be bridged to itself.")}) if self.device_type and self.device_type != self.bridge.device_type: raise ValidationError({ - 'bridge': _("Bridge interface ({bridge}) must belong to the same device type").format(bridge=self.bridge) + 'bridge': _( + "Bridge interface ({bridge}) must belong to the same device type" + ).format(bridge=self.bridge) }) if self.module_type and self.module_type != self.bridge.module_type: raise ValidationError({ - 'bridge': _("Bridge interface ({bridge}) must belong to the same module type").format(bridge=self.bridge) + 'bridge': _( + "Bridge interface ({bridge}) must belong to the same module type" + ).format(bridge=self.bridge) }) if self.rf_role and self.type not in WIRELESS_IFACE_TYPES: @@ -714,7 +724,9 @@ class DeviceBayTemplate(ComponentTemplateModel): def clean(self): if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT: raise ValidationError( - _("Subdevice role of device type ({device_type}) must be set to \"parent\" to allow device bays.").format(device_type=self.device_type) + _( + 'Subdevice role of device type ({device_type}) must be set to "parent" to allow device bays.' + ).format(device_type=self.device_type) ) def to_yaml(self): diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 31278a13c..ce9e5607f 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -10,7 +10,7 @@ from mptt.models import MPTTModel, TreeForeignKey from dcim.choices import * from dcim.constants import * -from dcim.fields import MACAddressField, WWNField +from dcim.fields import WWNField from netbox.choices import ColorChoices from netbox.models import OrganizationalModel, NetBoxModel from utilities.fields import ColorField, NaturalOrderingField @@ -505,11 +505,6 @@ class BaseInterface(models.Model): verbose_name=_('enabled'), default=True ) - mac_address = MACAddressField( - null=True, - blank=True, - verbose_name=_('MAC address') - ) mtu = models.PositiveIntegerField( blank=True, null=True, @@ -572,6 +567,14 @@ class BaseInterface(models.Model): blank=True, verbose_name=_('VLAN Translation Policy') ) + primary_mac_address = models.OneToOneField( + to='dcim.MACAddress', + on_delete=models.SET_NULL, + related_name='+', + blank=True, + null=True, + verbose_name=_('primary MAC address') + ) class Meta: abstract = True @@ -585,6 +588,14 @@ class BaseInterface(models.Model): 'qinq_svlan': _("Only Q-in-Q interfaces may specify a service VLAN.") }) + # Check that the primary MAC address (if any) is assigned to this interface + if self.primary_mac_address and self.primary_mac_address.assigned_object != self: + raise ValidationError({ + 'primary_mac_address': _("MAC address {mac_address} is not assigned to this interface.").format( + mac_address=self.primary_mac_address + ) + }) + def save(self, *args, **kwargs): # Remove untagged VLAN assignment for non-802.1Q interfaces @@ -609,6 +620,11 @@ class BaseInterface(models.Model): def count_fhrp_groups(self): return self.fhrp_group_assignments.count() + @cached_property + def mac_address(self): + if self.primary_mac_address: + return self.primary_mac_address.mac_address + class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEndpoint, TrackingModelMixin): """ @@ -738,6 +754,12 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd object_id_field='assigned_object_id', related_query_name='interface' ) + mac_addresses = GenericRelation( + to='dcim.MACAddress', + content_type_field='assigned_object_type', + object_id_field='assigned_object_id', + related_query_name='interface' + ) fhrp_group_assignments = GenericRelation( to='ipam.FHRPGroupAssignment', content_type_field='interface_type', @@ -976,6 +998,14 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd def l2vpn_termination(self): return self.l2vpn_terminations.first() + @cached_property + def connected_endpoints(self): + # If this is a virtual interface, return the remote endpoint of the connected + # virtual circuit, if any. + if self.is_virtual and hasattr(self, 'virtual_circuit_termination'): + return self.virtual_circuit_termination.peer_terminations + return super().connected_endpoints + # # Pass-through ports diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index a836c5d37..1fbffa54b 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -3,6 +3,7 @@ import yaml from functools import cached_property +from django.contrib.contenttypes.fields import GenericForeignKey from django.core.exceptions import ValidationError from django.core.files.storage import default_storage from django.core.validators import MaxValueValidator, MinValueValidator @@ -16,6 +17,7 @@ from django.utils.translation import gettext_lazy as _ from dcim.choices import * from dcim.constants import * +from dcim.fields import MACAddressField from extras.models import ConfigContextModel, CustomField from extras.querysets import ConfigContextModelQuerySet from netbox.choices import ColorChoices @@ -33,6 +35,7 @@ __all__ = ( 'Device', 'DeviceRole', 'DeviceType', + 'MACAddress', 'Manufacturer', 'Module', 'ModuleType', @@ -529,7 +532,10 @@ def update_interface_bridges(device, interface_templates, module=None): interface = Interface.objects.get(device=device, name=interface_template.resolve_name(module=module)) if interface_template.bridge: - interface.bridge = Interface.objects.get(device=device, name=interface_template.bridge.resolve_name(module=module)) + interface.bridge = Interface.objects.get( + device=device, + name=interface_template.bridge.resolve_name(module=module) + ) interface.full_clean() interface.save() @@ -906,7 +912,10 @@ class Device( }) if self.primary_ip4.assigned_object in vc_interfaces: pass - elif self.primary_ip4.nat_inside is not None and self.primary_ip4.nat_inside.assigned_object in vc_interfaces: + elif ( + self.primary_ip4.nat_inside is not None and + self.primary_ip4.nat_inside.assigned_object in vc_interfaces + ): pass else: raise ValidationError({ @@ -921,7 +930,10 @@ class Device( }) if self.primary_ip6.assigned_object in vc_interfaces: pass - elif self.primary_ip6.nat_inside is not None and self.primary_ip6.nat_inside.assigned_object in vc_interfaces: + elif ( + self.primary_ip6.nat_inside is not None and + self.primary_ip6.nat_inside.assigned_object in vc_interfaces + ): pass else: raise ValidationError({ @@ -975,9 +987,10 @@ class Device( 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 - ) + '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): @@ -1470,3 +1483,37 @@ class VirtualDeviceContext(PrimaryModel): raise ValidationError({ f'primary_ip{family}': _('Primary IP address must belong to an interface on the assigned device.') }) + + +# +# Addressing +# + +class MACAddress(PrimaryModel): + mac_address = MACAddressField( + verbose_name=_('MAC address') + ) + assigned_object_type = models.ForeignKey( + to='contenttypes.ContentType', + limit_choices_to=MACADDRESS_ASSIGNMENT_MODELS, + on_delete=models.PROTECT, + related_name='+', + blank=True, + null=True + ) + assigned_object_id = models.PositiveBigIntegerField( + blank=True, + null=True + ) + assigned_object = GenericForeignKey( + ct_field='assigned_object_type', + fk_field='assigned_object_id' + ) + + class Meta: + ordering = ('mac_address',) + verbose_name = _('MAC address') + verbose_name_plural = _('MAC addresses') + + def __str__(self): + return str(self.mac_address) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 08b7f5a35..78eb0ea4a 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -379,7 +379,9 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): min_height = top_device.position + top_device.device_type.u_height - self.starting_unit if self.u_height < min_height: raise ValidationError({ - 'u_height': _("Rack must be at least {min_height}U tall to house currently installed devices.").format(min_height=min_height) + 'u_height': _( + "Rack must be at least {min_height}U tall to house currently installed devices." + ).format(min_height=min_height) }) # Validate that the Rack's starting unit is less than or equal to the position of the lowest mounted Device diff --git a/netbox/dcim/search.py b/netbox/dcim/search.py index 45431cb05..6b03d8b43 100644 --- a/netbox/dcim/search.py +++ b/netbox/dcim/search.py @@ -98,19 +98,28 @@ class FrontPortIndex(SearchIndex): display_attrs = ('device', 'label', 'type', 'description') +@register_search +class MACAddressIndex(SearchIndex): + model = models.MACAddress + fields = ( + ('mac_address', 100), + ('description', 500), + ) + display_attrs = ('mac_address', 'interface') + + @register_search class InterfaceIndex(SearchIndex): model = models.Interface fields = ( ('name', 100), ('label', 200), - ('mac_address', 300), ('wwn', 300), ('description', 500), ('mtu', 2000), ('speed', 2000), ) - display_attrs = ('device', 'label', 'type', 'mac_address', 'wwn', 'description') + display_attrs = ('device', 'label', 'type', 'wwn', 'description') @register_search diff --git a/netbox/dcim/svg/racks.py b/netbox/dcim/svg/racks.py index 0f73095b5..81f8ad3a5 100644 --- a/netbox/dcim/svg/racks.py +++ b/netbox/dcim/svg/racks.py @@ -153,7 +153,10 @@ class RackElevationSVG: if self.rack.desc_units: y += int((position - self.rack.starting_unit) * self.unit_height) else: - y += int((self.rack.u_height - position + self.rack.starting_unit) * self.unit_height) - int(height * self.unit_height) + y += ( + int((self.rack.u_height - position + self.rack.starting_unit) * self.unit_height) - + int(height * self.unit_height) + ) return x, y diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index b7634626d..59d0845d5 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -29,6 +29,7 @@ __all__ = ( 'InterfaceTable', 'InventoryItemRoleTable', 'InventoryItemTable', + 'MACAddressTable', 'ModuleBayTable', 'PlatformTable', 'PowerOutletTable', @@ -42,6 +43,16 @@ MODULEBAY_STATUS = """ {% badge record.installed_module.get_status_display bg_color=record.installed_module.get_status_color %} """ +MACADDRESS_LINK = """ +{% if record.pk %} + {{ record.mac_address }} +{% endif %} +""" + +MACADDRESS_COPY_BUTTON = """ +{% copy_content record.pk prefix="macaddress_" %} +""" + # # Device roles @@ -380,7 +391,8 @@ class ConsolePortTable(ModularDeviceComponentTable, PathEndpointTable): model = models.ConsolePort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description', - 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created', 'last_updated', + 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created', + 'last_updated', ) default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description') @@ -420,7 +432,8 @@ class ConsoleServerPortTable(ModularDeviceComponentTable, PathEndpointTable): model = models.ConsoleServerPort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description', - 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created', 'last_updated', + 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created', + 'last_updated', ) default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description') @@ -588,6 +601,10 @@ class BaseInterfaceTable(NetBoxTable): verbose_name=_('Q-in-Q SVLAN'), linkify=True ) + primary_mac_address = tables.Column( + verbose_name=_('MAC Address'), + linkify=True + ) def value_ip_addresses(self, value): return ",".join([str(obj.address) for obj in value.all()]) @@ -634,15 +651,23 @@ class InterfaceTable(BaseInterfaceTable, ModularDeviceComponentTable, PathEndpoi url_name='dcim:interface_list' ) + # Override PathEndpointTable.connection to accommodate virtual circuits + connection = columns.TemplateColumn( + accessor='_path__destinations', + template_code=INTERFACE_LINKTERMINATION, + verbose_name=_('Connection'), + orderable=False + ) + class Meta(DeviceComponentTable.Meta): model = models.Interface fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', - 'speed', 'speed_formatted', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', - 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', - 'cable', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', - 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', - 'inventory_items', 'created', 'last_updated', + 'speed', 'speed_formatted', 'duplex', 'mode', 'primary_mac_address', 'wwn', 'poe_mode', 'poe_type', + 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', + 'mark_connected', 'cable', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', + 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', + 'qinq_svlan', 'inventory_items', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description') @@ -964,8 +989,8 @@ class InventoryItemTable(DeviceComponentTable): class Meta(NetBoxTable.Meta): model = models.InventoryItem fields = ( - 'pk', 'id', 'name', 'device', 'parent', 'component', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', - 'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'device', 'parent', 'component', 'label', 'status', 'role', 'manufacturer', 'part_id', + 'serial', 'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'device', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', @@ -983,8 +1008,8 @@ class DeviceInventoryItemTable(InventoryItemTable): class Meta(NetBoxTable.Meta): model = models.InventoryItem fields = ( - 'pk', 'id', 'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component', - 'description', 'discovered', 'tags', 'actions', + 'pk', 'id', 'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', + 'component', 'description', 'discovered', 'tags', 'actions', ) default_columns = ( 'pk', 'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component', @@ -1098,3 +1123,34 @@ class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable): default_columns = ( 'pk', 'name', 'identifier', 'status', 'tenant', 'primary_ip', ) + + +class MACAddressTable(NetBoxTable): + mac_address = tables.TemplateColumn( + template_code=MACADDRESS_LINK, + verbose_name=_('MAC Address') + ) + assigned_object = tables.Column( + linkify=True, + orderable=False, + verbose_name=_('Interface') + ) + assigned_object_parent = tables.Column( + accessor='assigned_object__parent_object', + linkify=True, + orderable=False, + verbose_name=_('Parent') + ) + tags = columns.TagColumn( + url_name='dcim:macaddress_list' + ) + actions = columns.ActionsColumn( + extra_buttons=MACADDRESS_COPY_BUTTON + ) + + class Meta(DeviceComponentTable.Meta): + model = models.MACAddress + fields = ( + 'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'created', 'last_updated', + ) + default_columns = ('pk', 'mac_address', 'assigned_object_parent', 'assigned_object') diff --git a/netbox/dcim/tables/template_code.py b/netbox/dcim/tables/template_code.py index 96ab803e6..e6f2c8817 100644 --- a/netbox/dcim/tables/template_code.py +++ b/netbox/dcim/tables/template_code.py @@ -10,6 +10,20 @@ LINKTERMINATION = """ {% endfor %} """ +INTERFACE_LINKTERMINATION = """ +{% load i18n %} +{% if record.is_virtual and record.virtual_circuit_termination %} + {% for termination in record.connected_endpoints %} + {{ termination.interface.parent_object }} + + {{ termination.interface }} + {% trans "via" %} + {{ termination.parent_object }} + {% if not forloop.last %}
{% endif %} + {% endfor %} +{% else %}""" + LINKTERMINATION + """{% endif %} +""" + CABLE_LENGTH = """ {% load helpers %} {% if record.length %}{{ record.length|floatformat:"-2" }} {{ record.length_unit }}{% endif %} @@ -314,6 +328,9 @@ INTERFACE_BUTTONS = """ {% if perms.ipam.add_ipaddress %}
  • IP Address
  • {% endif %} + {% if perms.dcim.add_macaddress %} +
  • MAC Address
  • + {% endif %} {% if perms.dcim.add_inventoryitem %}
  • Inventory Item
  • {% endif %} diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index f78722b67..c273e02dd 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -205,13 +205,41 @@ class LocationTest(APIViewTestCases.APIViewTestCase): Site.objects.bulk_create(sites) parent_locations = ( - Location.objects.create(site=sites[0], name='Parent Location 1', slug='parent-location-1', status=LocationStatusChoices.STATUS_ACTIVE), - Location.objects.create(site=sites[1], name='Parent Location 2', slug='parent-location-2', status=LocationStatusChoices.STATUS_ACTIVE), + Location.objects.create( + site=sites[0], + name='Parent Location 1', + slug='parent-location-1', + status=LocationStatusChoices.STATUS_ACTIVE, + ), + Location.objects.create( + site=sites[1], + name='Parent Location 2', + slug='parent-location-2', + status=LocationStatusChoices.STATUS_ACTIVE, + ), ) - Location.objects.create(site=sites[0], name='Location 1', slug='location-1', parent=parent_locations[0], status=LocationStatusChoices.STATUS_ACTIVE) - Location.objects.create(site=sites[0], name='Location 2', slug='location-2', parent=parent_locations[0], status=LocationStatusChoices.STATUS_ACTIVE) - Location.objects.create(site=sites[0], name='Location 3', slug='location-3', parent=parent_locations[0], status=LocationStatusChoices.STATUS_ACTIVE) + Location.objects.create( + site=sites[0], + name='Location 1', + slug='location-1', + parent=parent_locations[0], + status=LocationStatusChoices.STATUS_ACTIVE, + ) + Location.objects.create( + site=sites[0], + name='Location 2', + slug='location-2', + parent=parent_locations[0], + status=LocationStatusChoices.STATUS_ACTIVE, + ) + Location.objects.create( + site=sites[0], + name='Location 3', + slug='location-3', + parent=parent_locations[0], + status=LocationStatusChoices.STATUS_ACTIVE, + ) cls.create_data = [ { @@ -290,9 +318,24 @@ class RackTypeTest(APIViewTestCases.APIViewTestCase): Manufacturer.objects.bulk_create(manufacturers) rack_types = ( - RackType(manufacturer=manufacturers[0], model='Rack Type 1', slug='rack-type-1', form_factor=RackFormFactorChoices.TYPE_CABINET,), - RackType(manufacturer=manufacturers[0], model='Rack Type 2', slug='rack-type-2', form_factor=RackFormFactorChoices.TYPE_CABINET,), - RackType(manufacturer=manufacturers[0], model='Rack Type 3', slug='rack-type-3', form_factor=RackFormFactorChoices.TYPE_CABINET,), + RackType( + manufacturer=manufacturers[0], + model='Rack Type 1', + slug='rack-type-1', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), + RackType( + manufacturer=manufacturers[0], + model='Rack Type 2', + slug='rack-type-2', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), + RackType( + manufacturer=manufacturers[0], + model='Rack Type 3', + slug='rack-type-3', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), ) RackType.objects.bulk_create(rack_types) @@ -1050,10 +1093,18 @@ class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase): role = InventoryItemRole.objects.create(name='Inventory Item Role 1', slug='inventory-item-role-1') inventory_item_templates = ( - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturer, role=role), - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturer, role=role), - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturer, role=role), - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 4', manufacturer=manufacturer, role=role), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturer, role=role + ), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturer, role=role + ), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturer, role=role + ), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 4', manufacturer=manufacturer, role=role + ), ) for item in inventory_item_templates: item.save() @@ -1961,9 +2012,15 @@ class InventoryItemTest(APIViewTestCases.APIViewTestCase): ) Interface.objects.bulk_create(interfaces) - InventoryItem.objects.create(device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer, component=interfaces[0]) - InventoryItem.objects.create(device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer, component=interfaces[1]) - InventoryItem.objects.create(device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer, component=interfaces[2]) + InventoryItem.objects.create( + device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer, component=interfaces[0] + ) + InventoryItem.objects.create( + device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer, component=interfaces[1] + ) + InventoryItem.objects.create( + device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer, component=interfaces[2] + ) cls.create_data = [ { diff --git a/netbox/dcim/tests/test_cablepaths.py b/netbox/dcim/tests/test_cablepaths.py index b504d389a..1acc9a8a1 100644 --- a/netbox/dcim/tests/test_cablepaths.py +++ b/netbox/dcim/tests/test_cablepaths.py @@ -661,24 +661,64 @@ class CablePathTestCase(TestCase): ) cable5.save() path1 = self.assertPathExists( - ([interface1, interface2], cable1, frontport1_1, rearport1, cable3, rearport2, frontport2_1, cable4, [interface5, interface6]), + ( + [interface1, interface2], + cable1, + frontport1_1, + rearport1, + cable3, + rearport2, + frontport2_1, + cable4, + [interface5, interface6], + ), is_complete=True, - is_active=True + is_active=True, ) path2 = self.assertPathExists( - ([interface3, interface4], cable2, frontport1_2, rearport1, cable3, rearport2, frontport2_2, cable5, [interface7, interface8]), + ( + [interface3, interface4], + cable2, + frontport1_2, + rearport1, + cable3, + rearport2, + frontport2_2, + cable5, + [interface7, interface8], + ), is_complete=True, - is_active=True + is_active=True, ) path3 = self.assertPathExists( - ([interface5, interface6], cable4, frontport2_1, rearport2, cable3, rearport1, frontport1_1, cable1, [interface1, interface2]), + ( + [interface5, interface6], + cable4, + frontport2_1, + rearport2, + cable3, + rearport1, + frontport1_1, + cable1, + [interface1, interface2], + ), is_complete=True, - is_active=True + is_active=True, ) path4 = self.assertPathExists( - ([interface7, interface8], cable5, frontport2_2, rearport2, cable3, rearport1, frontport1_2, cable2, [interface3, interface4]), + ( + [interface7, interface8], + cable5, + frontport2_2, + rearport2, + cable3, + rearport1, + frontport1_2, + cable2, + [interface3, interface4], + ), is_complete=True, - is_active=True + is_active=True, ) self.assertEqual(CablePath.objects.count(), 4) @@ -1167,7 +1207,11 @@ class CablePathTestCase(TestCase): [IF1] --C1-- [CT1] """ interface1 = Interface.objects.create(device=self.device, name='Interface 1') - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) # Create cable 1 cable1 = Cable( @@ -1198,7 +1242,11 @@ class CablePathTestCase(TestCase): """ interface1 = Interface.objects.create(device=self.device, name='Interface 1') interface2 = Interface.objects.create(device=self.device, name='Interface 2') - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) # Create cable 1 cable1 = Cable( @@ -1214,7 +1262,11 @@ class CablePathTestCase(TestCase): ) # Create CT2 - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z') + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='Z' + ) # Check for partial path to site self.assertPathExists( @@ -1266,7 +1318,11 @@ class CablePathTestCase(TestCase): interface2 = Interface.objects.create(device=self.device, name='Interface 2') interface3 = Interface.objects.create(device=self.device, name='Interface 3') interface4 = Interface.objects.create(device=self.device, name='Interface 4') - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) # Create cable 1 cable1 = Cable( @@ -1282,7 +1338,11 @@ class CablePathTestCase(TestCase): ) # Create CT2 - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z') + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='Z' + ) # Check for partial path to site self.assertPathExists( @@ -1299,14 +1359,28 @@ class CablePathTestCase(TestCase): # Check for complete path in each direction self.assertPathExists( - ([interface1, interface2], cable1, circuittermination1, circuittermination2, cable2, [interface3, interface4]), + ( + [interface1, interface2], + cable1, + circuittermination1, + circuittermination2, + cable2, + [interface3, interface4], + ), is_complete=True, - is_active=True + is_active=True, ) self.assertPathExists( - ([interface3, interface4], cable2, circuittermination2, circuittermination1, cable1, [interface1, interface2]), + ( + [interface3, interface4], + cable2, + circuittermination2, + circuittermination1, + cable1, + [interface1, interface2], + ), is_complete=True, - is_active=True + is_active=True, ) self.assertEqual(CablePath.objects.count(), 2) @@ -1335,8 +1409,16 @@ class CablePathTestCase(TestCase): """ interface1 = Interface.objects.create(device=self.device, name='Interface 1') site2 = Site.objects.create(name='Site 2', slug='site-2') - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=site2, term_side='Z') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=site2, + term_side='Z' + ) # Create cable 1 cable1 = Cable( @@ -1365,8 +1447,16 @@ class CablePathTestCase(TestCase): """ interface1 = Interface.objects.create(device=self.device, name='Interface 1') providernetwork = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.circuit.provider) - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=providernetwork, term_side='Z') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=providernetwork, + term_side='Z' + ) # Create cable 1 cable1 = Cable( @@ -1413,8 +1503,15 @@ class CablePathTestCase(TestCase): frontport2_2 = FrontPort.objects.create( device=self.device, name='Front Port 2:2', rear_port=rearport2, rear_port_position=2 ) - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, term_side='Z' + ) # Create cables cable1 = Cable( @@ -1499,10 +1596,26 @@ class CablePathTestCase(TestCase): interface1 = Interface.objects.create(device=self.device, name='Interface 1') interface2 = Interface.objects.create(device=self.device, name='Interface 2') circuit2 = Circuit.objects.create(provider=self.circuit.provider, type=self.circuit.type, cid='Circuit 2') - circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A') - circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z') - circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, termination=self.site, term_side='A') - circuittermination4 = CircuitTermination.objects.create(circuit=circuit2, termination=self.site, term_side='Z') + circuittermination1 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='A' + ) + circuittermination2 = CircuitTermination.objects.create( + circuit=self.circuit, + termination=self.site, + term_side='Z' + ) + circuittermination3 = CircuitTermination.objects.create( + circuit=circuit2, + termination=self.site, + term_side='A' + ) + circuittermination4 = CircuitTermination.objects.create( + circuit=circuit2, + termination=self.site, + term_side='Z' + ) # Create cables cable1 = Cable( @@ -1706,45 +1819,95 @@ class CablePathTestCase(TestCase): ) cable3.save() self.assertPathExists( - (interface1, cable1, (frontport1_1, frontport1_2), rearport1, cable3, rearport2, (frontport2_1, frontport2_2)), - is_complete=False + ( + interface1, + cable1, + (frontport1_1, frontport1_2), + rearport1, + cable3, + rearport2, + (frontport2_1, frontport2_2), + ), + is_complete=False, ) self.assertPathExists( - (interface2, cable2, (frontport1_3, frontport1_4), rearport1, cable3, rearport2, (frontport2_3, frontport2_4)), - is_complete=False + ( + interface2, + cable2, + (frontport1_3, frontport1_4), + rearport1, + cable3, + rearport2, + (frontport2_3, frontport2_4), + ), + is_complete=False, ) self.assertEqual(CablePath.objects.count(), 2) # Create cables 4-5 - cable4 = Cable( - a_terminations=[frontport2_1, frontport2_2], - b_terminations=[interface3] - ) + cable4 = Cable(a_terminations=[frontport2_1, frontport2_2], b_terminations=[interface3]) cable4.save() - cable5 = Cable( - a_terminations=[frontport2_3, frontport2_4], - b_terminations=[interface4] - ) + cable5 = Cable(a_terminations=[frontport2_3, frontport2_4], b_terminations=[interface4]) cable5.save() path1 = self.assertPathExists( - (interface1, cable1, (frontport1_1, frontport1_2), rearport1, cable3, rearport2, (frontport2_1, frontport2_2), cable4, interface3), + ( + interface1, + cable1, + (frontport1_1, frontport1_2), + rearport1, + cable3, + rearport2, + (frontport2_1, frontport2_2), + cable4, + interface3, + ), is_complete=True, - is_active=True + is_active=True, ) path2 = self.assertPathExists( - (interface2, cable2, (frontport1_3, frontport1_4), rearport1, cable3, rearport2, (frontport2_3, frontport2_4), cable5, interface4), + ( + interface2, + cable2, + (frontport1_3, frontport1_4), + rearport1, + cable3, + rearport2, + (frontport2_3, frontport2_4), + cable5, + interface4, + ), is_complete=True, - is_active=True + is_active=True, ) path3 = self.assertPathExists( - (interface3, cable4, (frontport2_1, frontport2_2), rearport2, cable3, rearport1, (frontport1_1, frontport1_2), cable1, interface1), + ( + interface3, + cable4, + (frontport2_1, frontport2_2), + rearport2, + cable3, + rearport1, + (frontport1_1, frontport1_2), + cable1, + interface1, + ), is_complete=True, - is_active=True + is_active=True, ) path4 = self.assertPathExists( - (interface4, cable5, (frontport2_3, frontport2_4), rearport2, cable3, rearport1, (frontport1_3, frontport1_4), cable2, interface2), + ( + interface4, + cable5, + (frontport2_3, frontport2_4), + rearport2, + cable3, + rearport1, + (frontport1_3, frontport1_4), + cable2, + interface2, + ), is_complete=True, - is_active=True + is_active=True, ) self.assertEqual(CablePath.objects.count(), 4) @@ -1809,7 +1972,10 @@ class CablePathTestCase(TestCase): ) cable1.save() self.assertPathExists( - (interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4), (rearport2, rearport4), (frontport2, frontport4)), + ( + interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4), + (rearport2, rearport4), (frontport2, frontport4) + ), is_complete=False ) self.assertEqual(CablePath.objects.count(), 1) diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index 993c2fa4e..ede1e2a09 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -9,8 +9,8 @@ from ipam.models import ASN, IPAddress, RIR, VLAN, VLANTranslationPolicy, VRF from netbox.choices import ColorChoices, WeightUnitChoices from tenancy.models import Tenant, TenantGroup from users.models import User -from utilities.testing import ChangeLoggedFilterSetTests, create_test_device -from virtualization.models import Cluster, ClusterType, ClusterGroup +from utilities.testing import ChangeLoggedFilterSetTests, create_test_device, create_test_virtualmachine +from virtualization.models import Cluster, ClusterType, ClusterGroup, VMInterface, VirtualMachine from wireless.choices import WirelessChannelChoices, WirelessRoleChoices @@ -243,9 +243,41 @@ class SiteTestCase(TestCase, ChangeLoggedFilterSetTests): ASN.objects.bulk_create(asns) sites = ( - Site(name='Site 1', slug='site-1', region=regions[0], group=groups[0], tenant=tenants[0], status=SiteStatusChoices.STATUS_ACTIVE, facility='Facility 1', latitude=10, longitude=10, description='foobar1'), - Site(name='Site 2', slug='site-2', region=regions[1], group=groups[1], tenant=tenants[1], status=SiteStatusChoices.STATUS_PLANNED, facility='Facility 2', latitude=20, longitude=20, description='foobar2'), - Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2], tenant=tenants[2], status=SiteStatusChoices.STATUS_RETIRED, facility='Facility 3', latitude=30, longitude=30), + Site( + name='Site 1', + slug='site-1', + region=regions[0], + group=groups[0], + tenant=tenants[0], + status=SiteStatusChoices.STATUS_ACTIVE, + facility='Facility 1', + latitude=10, + longitude=10, + description='foobar1', + ), + Site( + name='Site 2', + slug='site-2', + region=regions[1], + group=groups[1], + tenant=tenants[1], + status=SiteStatusChoices.STATUS_PLANNED, + facility='Facility 2', + latitude=20, + longitude=20, + description='foobar2', + ), + Site( + name='Site 3', + slug='site-3', + region=regions[2], + group=groups[2], + tenant=tenants[2], + status=SiteStatusChoices.STATUS_RETIRED, + facility='Facility 3', + latitude=30, + longitude=30, + ), ) Site.objects.bulk_create(sites) sites[0].asns.set([asns[0]]) @@ -361,9 +393,33 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests): location.save() locations = ( - Location(name='Location 1A', slug='location-1a', site=sites[0], parent=parent_locations[0], status=LocationStatusChoices.STATUS_PLANNED, facility='Facility 1', description='foobar1'), - Location(name='Location 2A', slug='location-2a', site=sites[1], parent=parent_locations[1], status=LocationStatusChoices.STATUS_STAGING, facility='Facility 2', description='foobar2'), - Location(name='Location 3A', slug='location-3a', site=sites[2], parent=parent_locations[2], status=LocationStatusChoices.STATUS_DECOMMISSIONING, facility='Facility 3', description='foobar3'), + Location( + name='Location 1A', + slug='location-1a', + site=sites[0], + parent=parent_locations[0], + status=LocationStatusChoices.STATUS_PLANNED, + facility='Facility 1', + description='foobar1', + ), + Location( + name='Location 2A', + slug='location-2a', + site=sites[1], + parent=parent_locations[1], + status=LocationStatusChoices.STATUS_STAGING, + facility='Facility 2', + description='foobar2', + ), + Location( + name='Location 3A', + slug='location-3a', + site=sites[2], + parent=parent_locations[2], + status=LocationStatusChoices.STATUS_DECOMMISSIONING, + facility='Facility 3', + description='foobar3', + ), ) for location in locations: location.save() @@ -1222,10 +1278,22 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests): RearPortTemplate(device_type=device_types[1], name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C), ) RearPortTemplate.objects.bulk_create(rear_ports) - FrontPortTemplate.objects.bulk_create(( - FrontPortTemplate(device_type=device_types[0], name='Front Port 1', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[0]), - FrontPortTemplate(device_type=device_types[1], name='Front Port 2', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[1]), - )) + FrontPortTemplate.objects.bulk_create( + ( + FrontPortTemplate( + device_type=device_types[0], + name='Front Port 1', + type=PortTypeChoices.TYPE_8P8C, + rear_port=rear_ports[0], + ), + FrontPortTemplate( + device_type=device_types[1], + name='Front Port 2', + type=PortTypeChoices.TYPE_8P8C, + rear_port=rear_ports[1], + ), + ) + ) ModuleBayTemplate.objects.bulk_create(( ModuleBayTemplate(device_type=device_types[0], name='Module Bay 1'), ModuleBayTemplate(device_type=device_types[1], name='Module Bay 2'), @@ -1435,10 +1503,22 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): RearPortTemplate(module_type=module_types[1], name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C), ) RearPortTemplate.objects.bulk_create(rear_ports) - FrontPortTemplate.objects.bulk_create(( - FrontPortTemplate(module_type=module_types[0], name='Front Port 1', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[0]), - FrontPortTemplate(module_type=module_types[1], name='Front Port 2', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[1]), - )) + FrontPortTemplate.objects.bulk_create( + ( + FrontPortTemplate( + module_type=module_types[0], + name='Front Port 1', + type=PortTypeChoices.TYPE_8P8C, + rear_port=rear_ports[0], + ), + FrontPortTemplate( + module_type=module_types[1], + name='Front Port 2', + type=PortTypeChoices.TYPE_8P8C, + rear_port=rear_ports[1], + ), + ) + ) def test_q(self): params = {'q': 'foobar1'} @@ -1893,11 +1973,19 @@ class ModuleBayTemplateTestCase(TestCase, DeviceComponentTemplateFilterSetTests, ) ModuleType.objects.bulk_create(module_types) - ModuleBayTemplate.objects.bulk_create(( - ModuleBayTemplate(device_type=device_types[0], name='Module Bay 1', description='foobar1'), - ModuleBayTemplate(device_type=device_types[1], name='Module Bay 2', description='foobar2', module_type=module_types[0]), - ModuleBayTemplate(device_type=device_types[2], name='Module Bay 3', description='foobar3', module_type=module_types[1]), - )) + ModuleBayTemplate.objects.bulk_create( + ( + ModuleBayTemplate( + device_type=device_types[0], name='Module Bay 1', description='foobar1' + ), + ModuleBayTemplate( + device_type=device_types[1], name='Module Bay 2', description='foobar2', module_type=module_types[0] + ), + ModuleBayTemplate( + device_type=device_types[2], name='Module Bay 3', description='foobar3', module_type=module_types[1] + ), + ) + ) def test_name(self): params = {'name': ['Module Bay 1', 'Module Bay 2']} @@ -1996,9 +2084,15 @@ class InventoryItemTemplateTestCase(TestCase, DeviceComponentTemplateFilterSetTe item.save() child_inventory_item_templates = ( - InventoryItemTemplate(device_type=device_types[0], name='Inventory Item 1A', parent=inventory_item_templates[0]), - InventoryItemTemplate(device_type=device_types[1], name='Inventory Item 2A', parent=inventory_item_templates[1]), - InventoryItemTemplate(device_type=device_types[2], name='Inventory Item 3A', parent=inventory_item_templates[2]), + InventoryItemTemplate( + device_type=device_types[0], name='Inventory Item 1A', parent=inventory_item_templates[0] + ), + InventoryItemTemplate( + device_type=device_types[1], name='Inventory Item 2A', parent=inventory_item_templates[1] + ), + InventoryItemTemplate( + device_type=device_types[2], name='Inventory Item 3A', parent=inventory_item_templates[2] + ), ) for item in child_inventory_item_templates: item.save() @@ -2323,10 +2417,17 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests): PowerOutlet(device=devices[1], name='Power Outlet 2'), )) interfaces = ( - Interface(device=devices[0], name='Interface 1', mac_address='00-00-00-00-00-01'), - Interface(device=devices[1], name='Interface 2', mac_address='00-00-00-00-00-02'), + Interface(device=devices[0], name='Interface 1'), + Interface(device=devices[1], name='Interface 2'), ) Interface.objects.bulk_create(interfaces) + mac_addresses = ( + MACAddress(mac_address='00-00-00-00-00-01'), + MACAddress(mac_address='00-00-00-00-00-02'), + ) + MACAddress.objects.bulk_create(mac_addresses) + interfaces[0].mac_addresses.set([mac_addresses[0]]) + interfaces[1].mac_addresses.set([mac_addresses[1]]) rear_ports = ( RearPort(device=devices[0], name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C), RearPort(device=devices[1], name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C), @@ -2841,10 +2942,41 @@ class ConsolePortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[0], role=roles[0], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[0], + role=roles[0], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -3022,10 +3154,41 @@ class ConsoleServerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeL Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[2], role=roles[2], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[2], + role=roles[2], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -3051,9 +3214,15 @@ class ConsoleServerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeL ConsolePort.objects.bulk_create(console_ports) console_server_ports = ( - ConsoleServerPort(device=devices[0], module=modules[0], name='Console Server Port 1', label='A', description='First'), - ConsoleServerPort(device=devices[1], module=modules[1], name='Console Server Port 2', label='B', description='Second'), - ConsoleServerPort(device=devices[2], module=modules[2], name='Console Server Port 3', label='C', description='Third'), + ConsoleServerPort( + device=devices[0], module=modules[0], name='Console Server Port 1', label='A', description='First' + ), + ConsoleServerPort( + device=devices[1], module=modules[1], name='Console Server Port 2', label='B', description='Second' + ), + ConsoleServerPort( + device=devices[2], module=modules[2], name='Console Server Port 3', label='C', description='Third' + ), ) ConsoleServerPort.objects.bulk_create(console_server_ports) @@ -3203,10 +3372,41 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[2], role=roles[2], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[2], + role=roles[2], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -3232,9 +3432,33 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil PowerOutlet.objects.bulk_create(power_outlets) power_ports = ( - PowerPort(device=devices[0], module=modules[0], name='Power Port 1', label='A', maximum_draw=100, allocated_draw=50, description='First'), - PowerPort(device=devices[1], module=modules[1], name='Power Port 2', label='B', maximum_draw=200, allocated_draw=100, description='Second'), - PowerPort(device=devices[2], module=modules[2], name='Power Port 3', label='C', maximum_draw=300, allocated_draw=150, description='Third'), + PowerPort( + device=devices[0], + module=modules[0], + name='Power Port 1', + label='A', + maximum_draw=100, + allocated_draw=50, + description='First', + ), + PowerPort( + device=devices[1], + module=modules[1], + name='Power Port 2', + label='B', + maximum_draw=200, + allocated_draw=100, + description='Second', + ), + PowerPort( + device=devices[2], + module=modules[2], + name='Power Port 3', + label='C', + maximum_draw=300, + allocated_draw=150, + description='Third', + ), ) PowerPort.objects.bulk_create(power_ports) @@ -3392,10 +3616,41 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[2], role=roles[2], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[2], + role=roles[2], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -3421,9 +3676,33 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF PowerPort.objects.bulk_create(power_ports) power_outlets = ( - PowerOutlet(device=devices[0], module=modules[0], name='Power Outlet 1', label='A', feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A, description='First', color='ff0000'), - PowerOutlet(device=devices[1], module=modules[1], name='Power Outlet 2', label='B', feed_leg=PowerOutletFeedLegChoices.FEED_LEG_B, description='Second', color='00ff00'), - PowerOutlet(device=devices[2], module=modules[2], name='Power Outlet 3', label='C', feed_leg=PowerOutletFeedLegChoices.FEED_LEG_C, description='Third', color='0000ff'), + PowerOutlet( + device=devices[0], + module=modules[0], + name='Power Outlet 1', + label='A', + feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A, + description='First', + color='ff0000', + ), + PowerOutlet( + device=devices[1], + module=modules[1], + name='Power Outlet 2', + label='B', + feed_leg=PowerOutletFeedLegChoices.FEED_LEG_B, + description='Second', + color='00ff00', + ), + PowerOutlet( + device=devices[2], + module=modules[2], + name='Power Outlet 3', + label='C', + feed_leg=PowerOutletFeedLegChoices.FEED_LEG_C, + description='Third', + color='0000ff', + ), ) PowerOutlet.objects.bulk_create(power_outlets) @@ -3665,11 +3944,22 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil # Virtual Device Context Creation vdcs = ( - VirtualDeviceContext(device=devices[4], name='VDC 1', identifier=1, status=VirtualDeviceContextStatusChoices.STATUS_ACTIVE), - VirtualDeviceContext(device=devices[4], name='VDC 2', identifier=2, status=VirtualDeviceContextStatusChoices.STATUS_PLANNED), + VirtualDeviceContext( + device=devices[4], name='VDC 1', identifier=1, status=VirtualDeviceContextStatusChoices.STATUS_ACTIVE + ), + VirtualDeviceContext( + device=devices[4], name='VDC 2', identifier=2, status=VirtualDeviceContextStatusChoices.STATUS_PLANNED + ), ) VirtualDeviceContext.objects.bulk_create(vdcs) + mac_addresses = ( + MACAddress(mac_address='00-00-00-00-00-01'), + MACAddress(mac_address='00-00-00-00-00-02'), + MACAddress(mac_address='00-00-00-00-00-03'), + ) + MACAddress.objects.bulk_create(mac_addresses) + vlans = ( VLAN(name='SVLAN 1', vid=1001, qinq_role=VLANQinQRoleChoices.ROLE_SERVICE), VLAN(name='SVLAN 2', vid=1002, qinq_role=VLANQinQRoleChoices.ROLE_SERVICE), @@ -3695,7 +3985,6 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil mgmt_only=True, mtu=100, mode=InterfaceModeChoices.MODE_ACCESS, - mac_address='00-00-00-00-00-01', description='First', vrf=vrfs[0], speed=1000000, @@ -3721,7 +4010,6 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil mgmt_only=True, mtu=200, mode=InterfaceModeChoices.MODE_TAGGED, - mac_address='00-00-00-00-00-02', description='Second', vrf=vrfs[1], speed=1000000, @@ -3740,7 +4028,6 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil mgmt_only=False, mtu=300, mode=InterfaceModeChoices.MODE_TAGGED_ALL, - mac_address='00-00-00-00-00-03', description='Third', vrf=vrfs[2], speed=100000, @@ -3814,6 +4101,10 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil interfaces[6].vdcs.set([vdcs[0]]) interfaces[7].vdcs.set([vdcs[1]]) + interfaces[0].mac_addresses.set([mac_addresses[0]]) + interfaces[2].mac_addresses.set([mac_addresses[1]]) + interfaces[3].mac_addresses.set([mac_addresses[2]]) + # Cables Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[5]]).save() Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[6]]).save() @@ -3871,9 +4162,24 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil # Create child interfaces parent_interface = Interface.objects.first() child_interfaces = ( - Interface(device=parent_interface.device, name='Child 1', parent=parent_interface, type=InterfaceTypeChoices.TYPE_VIRTUAL), - Interface(device=parent_interface.device, name='Child 2', parent=parent_interface, type=InterfaceTypeChoices.TYPE_VIRTUAL), - Interface(device=parent_interface.device, name='Child 3', parent=parent_interface, type=InterfaceTypeChoices.TYPE_VIRTUAL), + Interface( + device=parent_interface.device, + name='Child 1', + parent=parent_interface, + type=InterfaceTypeChoices.TYPE_VIRTUAL, + ), + Interface( + device=parent_interface.device, + name='Child 2', + parent=parent_interface, + type=InterfaceTypeChoices.TYPE_VIRTUAL, + ), + Interface( + device=parent_interface.device, + name='Child 3', + parent=parent_interface, + type=InterfaceTypeChoices.TYPE_VIRTUAL, + ), ) Interface.objects.bulk_create(child_interfaces) @@ -3884,9 +4190,24 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil # Create bridged interfaces bridge_interface = Interface.objects.first() bridged_interfaces = ( - Interface(device=bridge_interface.device, name='Bridged 1', bridge=bridge_interface, type=InterfaceTypeChoices.TYPE_1GE_FIXED), - Interface(device=bridge_interface.device, name='Bridged 2', bridge=bridge_interface, type=InterfaceTypeChoices.TYPE_1GE_FIXED), - Interface(device=bridge_interface.device, name='Bridged 3', bridge=bridge_interface, type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface( + device=bridge_interface.device, + name='Bridged 1', + bridge=bridge_interface, + type=InterfaceTypeChoices.TYPE_1GE_FIXED, + ), + Interface( + device=bridge_interface.device, + name='Bridged 2', + bridge=bridge_interface, + type=InterfaceTypeChoices.TYPE_1GE_FIXED, + ), + Interface( + device=bridge_interface.device, + name='Bridged 3', + bridge=bridge_interface, + type=InterfaceTypeChoices.TYPE_1GE_FIXED, + ), ) Interface.objects.bulk_create(bridged_interfaces) @@ -4119,10 +4440,41 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[2], role=roles[2], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[2], + role=roles[2], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -4152,12 +4504,63 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil RearPort.objects.bulk_create(rear_ports) front_ports = ( - FrontPort(device=devices[0], module=modules[0], name='Front Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED, rear_port=rear_ports[0], rear_port_position=1, description='First'), - FrontPort(device=devices[1], module=modules[1], name='Front Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN, rear_port=rear_ports[1], rear_port_position=2, description='Second'), - FrontPort(device=devices[2], module=modules[2], name='Front Port 3', label='C', type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE, rear_port=rear_ports[2], rear_port_position=3, description='Third'), - FrontPort(device=devices[3], name='Front Port 4', label='D', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[3], rear_port_position=1), - FrontPort(device=devices[3], name='Front Port 5', label='E', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[4], rear_port_position=1), - FrontPort(device=devices[3], name='Front Port 6', label='F', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[5], rear_port_position=1), + FrontPort( + device=devices[0], + module=modules[0], + name='Front Port 1', + label='A', + type=PortTypeChoices.TYPE_8P8C, + color=ColorChoices.COLOR_RED, + rear_port=rear_ports[0], + rear_port_position=1, + description='First', + ), + FrontPort( + device=devices[1], + module=modules[1], + name='Front Port 2', + label='B', + type=PortTypeChoices.TYPE_110_PUNCH, + color=ColorChoices.COLOR_GREEN, + rear_port=rear_ports[1], + rear_port_position=2, + description='Second', + ), + FrontPort( + device=devices[2], + module=modules[2], + name='Front Port 3', + label='C', + type=PortTypeChoices.TYPE_BNC, + color=ColorChoices.COLOR_BLUE, + rear_port=rear_ports[2], + rear_port_position=3, + description='Third', + ), + FrontPort( + device=devices[3], + name='Front Port 4', + label='D', + type=PortTypeChoices.TYPE_FC, + rear_port=rear_ports[3], + rear_port_position=1, + ), + FrontPort( + device=devices[3], + name='Front Port 5', + label='E', + type=PortTypeChoices.TYPE_FC, + rear_port=rear_ports[4], + rear_port_position=1, + ), + FrontPort( + device=devices[3], + name='Front Port 6', + label='F', + type=PortTypeChoices.TYPE_FC, + rear_port=rear_ports[5], + rear_port_position=1, + ), ) FrontPort.objects.bulk_create(front_ports) @@ -4309,10 +4712,41 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), - Device(name=None, device_type=device_types[2], role=roles[2], site=sites[3], status='offline'), # For cable connections + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), + # For cable connections + Device( + name=None, + device_type=device_types[2], + role=roles[2], + site=sites[3], + status='offline' + ), ) Device.objects.bulk_create(devices) @@ -4332,9 +4766,36 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt Module.objects.bulk_create(modules) rear_ports = ( - RearPort(device=devices[0], module=modules[0], name='Rear Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED, positions=1, description='First'), - RearPort(device=devices[1], module=modules[1], name='Rear Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN, positions=2, description='Second'), - RearPort(device=devices[2], module=modules[2], name='Rear Port 3', label='C', type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE, positions=3, description='Third'), + RearPort( + device=devices[0], + module=modules[0], + name='Rear Port 1', + label='A', + type=PortTypeChoices.TYPE_8P8C, + color=ColorChoices.COLOR_RED, + positions=1, + description='First', + ), + RearPort( + device=devices[1], + module=modules[1], + name='Rear Port 2', + label='B', + type=PortTypeChoices.TYPE_110_PUNCH, + color=ColorChoices.COLOR_GREEN, + positions=2, + description='Second', + ), + RearPort( + device=devices[2], + module=modules[2], + name='Rear Port 3', + label='C', + type=PortTypeChoices.TYPE_BNC, + color=ColorChoices.COLOR_BLUE, + positions=3, + description='Third', + ), RearPort(device=devices[3], name='Rear Port 4', label='D', type=PortTypeChoices.TYPE_FC, positions=4), RearPort(device=devices[3], name='Rear Port 5', label='E', type=PortTypeChoices.TYPE_FC, positions=5), RearPort(device=devices[3], name='Rear Port 6', label='F', type=PortTypeChoices.TYPE_FC, positions=6), @@ -4491,9 +4952,33 @@ class ModuleBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), ) Device.objects.bulk_create(devices) @@ -4639,9 +5124,33 @@ class DeviceBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0], status='active'), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1], status='planned'), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2], status='offline'), + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + status='active', + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + status='planned', + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + status='offline', + ), ) Device.objects.bulk_create(devices) @@ -4773,9 +5282,30 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_types[0], role=roles[0], site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_types[1], role=roles[1], site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_types[2], role=roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device( + name='Device 1', + device_type=device_types[0], + role=roles[0], + site=sites[0], + location=locations[0], + rack=racks[0], + ), + Device( + name='Device 2', + device_type=device_types[1], + role=roles[1], + site=sites[1], + location=locations[1], + rack=racks[1], + ), + Device( + name='Device 3', + device_type=device_types[2], + role=roles[2], + site=sites[2], + location=locations[2], + rack=racks[2], + ), ) Device.objects.bulk_create(devices) @@ -4793,9 +5323,48 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): ) inventory_items = ( - InventoryItem(device=devices[0], role=roles[0], manufacturer=manufacturers[0], name='Inventory Item 1', label='A', part_id='1001', serial='ABC', asset_tag='1001', discovered=True, status=ModuleStatusChoices.STATUS_ACTIVE, description='First', component=components[0]), - InventoryItem(device=devices[1], role=roles[1], manufacturer=manufacturers[1], name='Inventory Item 2', label='B', part_id='1002', serial='DEF', asset_tag='1002', discovered=True, status=ModuleStatusChoices.STATUS_PLANNED, description='Second', component=components[1]), - InventoryItem(device=devices[2], role=roles[2], manufacturer=manufacturers[2], name='Inventory Item 3', label='C', part_id='1003', serial='GHI', asset_tag='1003', discovered=False, status=ModuleStatusChoices.STATUS_FAILED, description='Third', component=components[2]), + InventoryItem( + device=devices[0], + role=roles[0], + manufacturer=manufacturers[0], + name='Inventory Item 1', + label='A', + part_id='1001', + serial='ABC', + asset_tag='1001', + discovered=True, + status=ModuleStatusChoices.STATUS_ACTIVE, + description='First', + component=components[0], + ), + InventoryItem( + device=devices[1], + role=roles[1], + manufacturer=manufacturers[1], + name='Inventory Item 2', + label='B', + part_id='1002', + serial='DEF', + asset_tag='1002', + discovered=True, + status=ModuleStatusChoices.STATUS_PLANNED, + description='Second', + component=components[1], + ), + InventoryItem( + device=devices[2], + role=roles[2], + manufacturer=manufacturers[2], + name='Inventory Item 3', + label='C', + part_id='1003', + serial='GHI', + asset_tag='1003', + discovered=False, + status=ModuleStatusChoices.STATUS_FAILED, + description='Third', + component=components[2], + ), ) for i in inventory_items: i.save() @@ -5112,12 +5681,60 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests): role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') devices = ( - Device(name='Device 1', device_type=device_type, role=role, site=sites[0], rack=racks[0], location=locations[0], position=1), - Device(name='Device 2', device_type=device_type, role=role, site=sites[0], rack=racks[0], location=locations[0], position=2), - Device(name='Device 3', device_type=device_type, role=role, site=sites[1], rack=racks[1], location=locations[1], position=1), - Device(name='Device 4', device_type=device_type, role=role, site=sites[1], rack=racks[1], location=locations[1], position=2), - Device(name='Device 5', device_type=device_type, role=role, site=sites[2], rack=racks[2], location=locations[2], position=1), - Device(name='Device 6', device_type=device_type, role=role, site=sites[2], rack=racks[2], location=locations[2], position=2), + Device( + name='Device 1', + device_type=device_type, + role=role, + site=sites[0], + rack=racks[0], + location=locations[0], + position=1, + ), + Device( + name='Device 2', + device_type=device_type, + role=role, + site=sites[0], + rack=racks[0], + location=locations[0], + position=2, + ), + Device( + name='Device 3', + device_type=device_type, + role=role, + site=sites[1], + rack=racks[1], + location=locations[1], + position=1, + ), + Device( + name='Device 4', + device_type=device_type, + role=role, + site=sites[1], + rack=racks[1], + location=locations[1], + position=2, + ), + Device( + name='Device 5', + device_type=device_type, + role=role, + site=sites[2], + rack=racks[2], + location=locations[2], + position=1, + ), + Device( + name='Device 6', + device_type=device_type, + role=role, + site=sites[2], + rack=racks[2], + location=locations[2], + position=2, + ), ) Device.objects.bulk_create(devices) @@ -5842,3 +6459,80 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) params = {'primary_ip6_id': [addresses[2].pk]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0) + + +class MACAddressTestCase(TestCase, ChangeLoggedFilterSetTests): + queryset = MACAddress.objects.all() + filterset = MACAddressFilterSet + + @classmethod + def setUpTestData(cls): + devices = ( + create_test_device('Device 1'), + create_test_device('Device 2'), + create_test_device('Device 3'), + ) + interfaces = ( + Interface(device=devices[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[1], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + ) + Interface.objects.bulk_create(interfaces) + + virtual_machines = ( + create_test_virtualmachine('Virtual Machine 1'), + create_test_virtualmachine('Virtual Machine 2'), + create_test_virtualmachine('Virtual Machine 3'), + ) + vm_interfaces = ( + VMInterface(virtual_machine=virtual_machines[0], name='Interface 1'), + VMInterface(virtual_machine=virtual_machines[1], name='Interface 2'), + VMInterface(virtual_machine=virtual_machines[2], name='Interface 3'), + ) + VMInterface.objects.bulk_create(vm_interfaces) + + mac_addresses = ( + # Device MACs + MACAddress(mac_address='00-00-00-01-01-01', assigned_object=interfaces[0]), + MACAddress(mac_address='00-00-00-02-01-01', assigned_object=interfaces[1]), + MACAddress(mac_address='00-00-00-03-01-01', assigned_object=interfaces[2]), + MACAddress(mac_address='00-00-00-03-01-02', assigned_object=interfaces[2]), + # VM MACs + MACAddress(mac_address='00-00-00-04-01-01', assigned_object=vm_interfaces[0]), + MACAddress(mac_address='00-00-00-05-01-01', assigned_object=vm_interfaces[1]), + MACAddress(mac_address='00-00-00-06-01-01', assigned_object=vm_interfaces[2]), + MACAddress(mac_address='00-00-00-06-01-02', assigned_object=vm_interfaces[2]), + ) + MACAddress.objects.bulk_create(mac_addresses) + + def test_mac_address(self): + params = {'mac_address': ['00-00-00-01-01-01', '00-00-00-02-01-01']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_device(self): + devices = Device.objects.all()[:2] + params = {'device_id': [devices[0].pk, devices[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'device': [devices[0].name, devices[1].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_virtual_machine(self): + virtual_machines = VirtualMachine.objects.all()[:2] + params = {'virtual_machine_id': [virtual_machines[0].pk, virtual_machines[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'virtual_machine': [virtual_machines[0].name, virtual_machines[1].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_interface(self): + interfaces = Interface.objects.all()[:2] + params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'interface': [interfaces[0].name, interfaces[1].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_vminterface(self): + vm_interfaces = VMInterface.objects.all()[:2] + params = {'vminterface_id': [vm_interfaces[0].pk, vm_interfaces[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'vminterface': [vm_interfaces[0].name, vm_interfaces[1].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 8d43d67ea..ff1eddd56 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -612,14 +612,31 @@ class DeviceTestCase(TestCase): device_role = DeviceRole.objects.first() # Device with site only should pass - Device(name='device1', site=sites[0], device_type=device_type, role=device_role).full_clean() + Device( + name='device1', + site=sites[0], + device_type=device_type, + role=device_role + ).full_clean() # Device with site, cluster non-site should pass - Device(name='device1', site=sites[0], device_type=device_type, role=device_role, cluster=clusters[2]).full_clean() + Device( + name='device1', + site=sites[0], + device_type=device_type, + role=device_role, + cluster=clusters[2] + ).full_clean() # Device with mismatched site & cluster should fail with self.assertRaises(ValidationError): - Device(name='device1', site=sites[0], device_type=device_type, role=device_role, cluster=clusters[1]).full_clean() + Device( + name='device1', + site=sites[0], + device_type=device_type, + role=device_role, + cluster=clusters[1] + ).full_clean() class ModuleBayTestCase(TestCase): @@ -636,7 +653,9 @@ class ModuleBayTestCase(TestCase): # Create a CustomField with a default value & assign it to all component models location = Location.objects.create(name='Location 1', slug='location-1', site=site) rack = Rack.objects.create(name='Rack 1', site=site) - device = Device.objects.create(name='Device 1', device_type=device_type, role=device_role, site=site, location=location, rack=rack) + device = Device.objects.create( + name='Device 1', device_type=device_type, role=device_role, site=site, location=location, rack=rack + ) module_bays = ( ModuleBay(device=device, name='Module Bay 1', label='A', description='First'), diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index dc3e74ae1..c2c5b6a01 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -196,9 +196,27 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase): tenant = Tenant.objects.create(name='Tenant 1', slug='tenant-1') locations = ( - Location(name='Location 1', slug='location-1', site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant), - Location(name='Location 2', slug='location-2', site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant), - Location(name='Location 3', slug='location-3', site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant), + Location( + name='Location 1', + slug='location-1', + site=site, + status=LocationStatusChoices.STATUS_ACTIVE, + tenant=tenant, + ), + Location( + name='Location 2', + slug='location-2', + site=site, + status=LocationStatusChoices.STATUS_ACTIVE, + tenant=tenant, + ), + Location( + name='Location 3', + slug='location-3', + site=site, + status=LocationStatusChoices.STATUS_ACTIVE, + tenant=tenant, + ), ) for location in locations: location.save() @@ -346,9 +364,24 @@ class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase): Manufacturer.objects.bulk_create(manufacturers) rack_types = ( - RackType(manufacturer=manufacturers[0], model='RackType 1', slug='rack-type-1', form_factor=RackFormFactorChoices.TYPE_CABINET,), - RackType(manufacturer=manufacturers[0], model='RackType 2', slug='rack-type-2', form_factor=RackFormFactorChoices.TYPE_CABINET,), - RackType(manufacturer=manufacturers[0], model='RackType 3', slug='rack-type-3', form_factor=RackFormFactorChoices.TYPE_CABINET,), + RackType( + manufacturer=manufacturers[0], + model='RackType 1', + slug='rack-type-1', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), + RackType( + manufacturer=manufacturers[0], + model='RackType 2', + slug='rack-type-2', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), + RackType( + manufacturer=manufacturers[0], + model='RackType 3', + slug='rack-type-3', + form_factor=RackFormFactorChoices.TYPE_CABINET, + ), ) RackType.objects.bulk_create(rack_types) @@ -692,9 +725,15 @@ class DeviceTypeTestCase( ) RearPortTemplate.objects.bulk_create(rear_ports) front_ports = ( - FrontPortTemplate(device_type=devicetype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1), - FrontPortTemplate(device_type=devicetype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1), - FrontPortTemplate(device_type=devicetype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1), + FrontPortTemplate( + device_type=devicetype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1 + ), + FrontPortTemplate( + device_type=devicetype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1 + ), + FrontPortTemplate( + device_type=devicetype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1 + ), ) FrontPortTemplate.objects.bulk_create(front_ports) @@ -1081,9 +1120,15 @@ class ModuleTypeTestCase( ) RearPortTemplate.objects.bulk_create(rear_ports) front_ports = ( - FrontPortTemplate(module_type=moduletype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1), - FrontPortTemplate(module_type=moduletype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1), - FrontPortTemplate(module_type=moduletype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1), + FrontPortTemplate( + module_type=moduletype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1 + ), + FrontPortTemplate( + module_type=moduletype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1 + ), + FrontPortTemplate( + module_type=moduletype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1 + ), ) FrontPortTemplate.objects.bulk_create(front_ports) @@ -1453,11 +1498,19 @@ class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas ) RearPortTemplate.objects.bulk_create(rearports) - FrontPortTemplate.objects.bulk_create(( - FrontPortTemplate(device_type=devicetype, name='Front Port Template 1', rear_port=rearports[0], rear_port_position=1), - FrontPortTemplate(device_type=devicetype, name='Front Port Template 2', rear_port=rearports[1], rear_port_position=1), - FrontPortTemplate(device_type=devicetype, name='Front Port Template 3', rear_port=rearports[2], rear_port_position=1), - )) + FrontPortTemplate.objects.bulk_create( + ( + FrontPortTemplate( + device_type=devicetype, name='Front Port Template 1', rear_port=rearports[0], rear_port_position=1 + ), + FrontPortTemplate( + device_type=devicetype, name='Front Port Template 2', rear_port=rearports[1], rear_port_position=1 + ), + FrontPortTemplate( + device_type=devicetype, name='Front Port Template 3', rear_port=rearports[2], rear_port_position=1 + ), + ) + ) cls.form_data = { 'device_type': devicetype.pk, @@ -1550,7 +1603,12 @@ class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas @classmethod def setUpTestData(cls): manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1', subdevice_role=SubdeviceRoleChoices.ROLE_PARENT) + devicetype = DeviceType.objects.create( + manufacturer=manufacturer, + model='Device Type 1', + slug='device-type-1', + subdevice_role=SubdeviceRoleChoices.ROLE_PARENT + ) DeviceBayTemplate.objects.bulk_create(( DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 1'), @@ -1584,12 +1642,20 @@ class InventoryItemTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTes Manufacturer(name='Manufacturer 2', slug='manufacturer-2'), ) Manufacturer.objects.bulk_create(manufacturers) - devicetype = DeviceType.objects.create(manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1') + devicetype = DeviceType.objects.create( + manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1' + ) inventory_item_templates = ( - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturers[0]), - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturers[0]), - InventoryItemTemplate(device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturers[0]), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturers[0] + ), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturers[0] + ), + InventoryItemTemplate( + device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturers[0] + ), ) for item in inventory_item_templates: item.save() @@ -1741,9 +1807,30 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase): Platform.objects.bulk_create(platforms) devices = ( - Device(name='Device 1', site=sites[0], rack=racks[0], device_type=devicetypes[0], role=roles[0], platform=platforms[0]), - Device(name='Device 2', site=sites[0], rack=racks[0], device_type=devicetypes[0], role=roles[0], platform=platforms[0]), - Device(name='Device 3', site=sites[0], rack=racks[0], device_type=devicetypes[0], role=roles[0], platform=platforms[0]), + Device( + name='Device 1', + site=sites[0], + rack=racks[0], + device_type=devicetypes[0], + role=roles[0], + platform=platforms[0], + ), + Device( + name='Device 2', + site=sites[0], + rack=racks[0], + device_type=devicetypes[0], + role=roles[0], + platform=platforms[0], + ), + Device( + name='Device 3', + site=sites[0], + rack=racks[0], + device_type=devicetypes[0], + role=roles[0], + platform=platforms[0], + ), ) Device.objects.bulk_create(devices) @@ -1778,10 +1865,22 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - "role,manufacturer,device_type,status,name,site,location,rack,position,face,virtual_chassis,vc_position,vc_priority", - "Device Role 1,Manufacturer 1,Device Type 1,active,Device 4,Site 1,Location 1,Rack 1,10,front,Virtual Chassis 1,1,10", - "Device Role 1,Manufacturer 1,Device Type 1,active,Device 5,Site 1,Location 1,Rack 1,20,front,Virtual Chassis 1,2,20", - "Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front,Virtual Chassis 1,3,30", + ( + "role,manufacturer,device_type,status,name,site,location,rack,position,face,virtual_chassis," + "vc_position,vc_priority" + ), + ( + "Device Role 1,Manufacturer 1,Device Type 1,active,Device 4,Site 1,Location 1,Rack 1,10,front," + "Virtual Chassis 1,1,10" + ), + ( + "Device Role 1,Manufacturer 1,Device Type 1,active,Device 5,Site 1,Location 1,Rack 1,20,front," + "Virtual Chassis 1,2,20" + ), + ( + "Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front," + "Virtual Chassis 1,3,30" + ), ) cls.csv_update_data = ( @@ -2508,7 +2607,6 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase): 'enabled': False, 'bridge': interfaces[4].pk, 'lag': interfaces[3].pk, - 'mac_address': EUI('01:02:03:04:05:06'), 'wwn': EUI('01:02:03:04:05:06:07:08', version=64), 'mtu': 65000, 'speed': 1000000, @@ -2533,7 +2631,6 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase): 'enabled': False, 'bridge': interfaces[4].pk, 'lag': interfaces[3].pk, - 'mac_address': EUI('01:02:03:04:05:06'), 'wwn': EUI('01:02:03:04:05:06:07:08', version=64), 'mtu': 2000, 'speed': 100000, @@ -2554,7 +2651,6 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase): 'type': InterfaceTypeChoices.TYPE_1GE_FIXED, 'enabled': True, 'lag': interfaces[3].pk, - 'mac_address': EUI('01:02:03:04:05:06'), 'wwn': EUI('01:02:03:04:05:06:07:08', version=64), 'mtu': 2000, 'speed': 1000000, @@ -2887,9 +2983,15 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase): ) InventoryItemRole.objects.bulk_create(roles) - inventory_item1 = InventoryItem.objects.create(device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer) - inventory_item2 = InventoryItem.objects.create(device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer) - inventory_item3 = InventoryItem.objects.create(device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer) + inventory_item1 = InventoryItem.objects.create( + device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer + ) + inventory_item2 = InventoryItem.objects.create( + device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer + ) + inventory_item3 = InventoryItem.objects.create( + device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer + ) tags = create_tags('Alpha', 'Bravo', 'Charlie') diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 627136bf9..bcfd32707 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -6,327 +6,144 @@ from . import views app_name = 'dcim' urlpatterns = [ - # Regions - path('regions/', views.RegionListView.as_view(), name='region_list'), - path('regions/add/', views.RegionEditView.as_view(), name='region_add'), - path('regions/import/', views.RegionBulkImportView.as_view(), name='region_import'), - path('regions/edit/', views.RegionBulkEditView.as_view(), name='region_bulk_edit'), - path('regions/delete/', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'), + path('regions/', include(get_model_urls('dcim', 'region', detail=False))), path('regions//', include(get_model_urls('dcim', 'region'))), - # Site groups - path('site-groups/', views.SiteGroupListView.as_view(), name='sitegroup_list'), - path('site-groups/add/', views.SiteGroupEditView.as_view(), name='sitegroup_add'), - path('site-groups/import/', views.SiteGroupBulkImportView.as_view(), name='sitegroup_import'), - path('site-groups/edit/', views.SiteGroupBulkEditView.as_view(), name='sitegroup_bulk_edit'), - path('site-groups/delete/', views.SiteGroupBulkDeleteView.as_view(), name='sitegroup_bulk_delete'), + path('site-groups/', include(get_model_urls('dcim', 'sitegroup', detail=False))), path('site-groups//', include(get_model_urls('dcim', 'sitegroup'))), - # Sites - path('sites/', views.SiteListView.as_view(), name='site_list'), - path('sites/add/', views.SiteEditView.as_view(), name='site_add'), - path('sites/import/', views.SiteBulkImportView.as_view(), name='site_import'), - path('sites/edit/', views.SiteBulkEditView.as_view(), name='site_bulk_edit'), - path('sites/delete/', views.SiteBulkDeleteView.as_view(), name='site_bulk_delete'), + path('sites/', include(get_model_urls('dcim', 'site', detail=False))), path('sites//', include(get_model_urls('dcim', 'site'))), - # Locations - path('locations/', views.LocationListView.as_view(), name='location_list'), - path('locations/add/', views.LocationEditView.as_view(), name='location_add'), - path('locations/import/', views.LocationBulkImportView.as_view(), name='location_import'), - path('locations/edit/', views.LocationBulkEditView.as_view(), name='location_bulk_edit'), - path('locations/delete/', views.LocationBulkDeleteView.as_view(), name='location_bulk_delete'), + path('locations/', include(get_model_urls('dcim', 'location', detail=False))), path('locations//', include(get_model_urls('dcim', 'location'))), - # Rack roles - path('rack-roles/', views.RackRoleListView.as_view(), name='rackrole_list'), - path('rack-roles/add/', views.RackRoleEditView.as_view(), name='rackrole_add'), - path('rack-roles/import/', views.RackRoleBulkImportView.as_view(), name='rackrole_import'), - path('rack-roles/edit/', views.RackRoleBulkEditView.as_view(), name='rackrole_bulk_edit'), - path('rack-roles/delete/', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'), + path('rack-roles/', include(get_model_urls('dcim', 'rackrole', detail=False))), path('rack-roles//', include(get_model_urls('dcim', 'rackrole'))), - # Rack reservations - path('rack-reservations/', views.RackReservationListView.as_view(), name='rackreservation_list'), - path('rack-reservations/add/', views.RackReservationEditView.as_view(), name='rackreservation_add'), - path('rack-reservations/import/', views.RackReservationImportView.as_view(), name='rackreservation_import'), - path('rack-reservations/edit/', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'), - path('rack-reservations/delete/', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'), + path('rack-reservations/', include(get_model_urls('dcim', 'rackreservation', detail=False))), path('rack-reservations//', include(get_model_urls('dcim', 'rackreservation'))), - # Racks - path('racks/', views.RackListView.as_view(), name='rack_list'), - path('rack-elevations/', views.RackElevationListView.as_view(), name='rack_elevation_list'), - path('racks/add/', views.RackEditView.as_view(), name='rack_add'), - path('racks/import/', views.RackBulkImportView.as_view(), name='rack_import'), - path('racks/edit/', views.RackBulkEditView.as_view(), name='rack_bulk_edit'), - path('racks/delete/', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'), + path('racks/', include(get_model_urls('dcim', 'rack', detail=False))), path('racks//', include(get_model_urls('dcim', 'rack'))), + path('rack-elevations/', views.RackElevationListView.as_view(), name='rack_elevation_list'), - # Rack Types - path('rack-types/', views.RackTypeListView.as_view(), name='racktype_list'), - path('rack-types/add/', views.RackTypeEditView.as_view(), name='racktype_add'), - path('rack-types/import/', views.RackTypeBulkImportView.as_view(), name='racktype_import'), - path('rack-types/edit/', views.RackTypeBulkEditView.as_view(), name='racktype_bulk_edit'), - path('rack-types/delete/', views.RackTypeBulkDeleteView.as_view(), name='racktype_bulk_delete'), + path('rack-types/', include(get_model_urls('dcim', 'racktype', detail=False))), path('rack-types//', include(get_model_urls('dcim', 'racktype'))), - # Manufacturers - path('manufacturers/', views.ManufacturerListView.as_view(), name='manufacturer_list'), - path('manufacturers/add/', views.ManufacturerEditView.as_view(), name='manufacturer_add'), - path('manufacturers/import/', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'), - path('manufacturers/edit/', views.ManufacturerBulkEditView.as_view(), name='manufacturer_bulk_edit'), - path('manufacturers/delete/', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'), + path('manufacturers/', include(get_model_urls('dcim', 'manufacturer', detail=False))), path('manufacturers//', include(get_model_urls('dcim', 'manufacturer'))), - # Device types - path('device-types/', views.DeviceTypeListView.as_view(), name='devicetype_list'), - path('device-types/add/', views.DeviceTypeEditView.as_view(), name='devicetype_add'), - path('device-types/import/', views.DeviceTypeImportView.as_view(), name='devicetype_import'), - path('device-types/edit/', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'), - path('device-types/delete/', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'), + path('device-types/', include(get_model_urls('dcim', 'devicetype', detail=False))), path('device-types//', include(get_model_urls('dcim', 'devicetype'))), - # Module types - path('module-types/', views.ModuleTypeListView.as_view(), name='moduletype_list'), - path('module-types/add/', views.ModuleTypeEditView.as_view(), name='moduletype_add'), - path('module-types/import/', views.ModuleTypeImportView.as_view(), name='moduletype_import'), - path('module-types/edit/', views.ModuleTypeBulkEditView.as_view(), name='moduletype_bulk_edit'), - path('module-types/delete/', views.ModuleTypeBulkDeleteView.as_view(), name='moduletype_bulk_delete'), + path('module-types/', include(get_model_urls('dcim', 'moduletype', detail=False))), path('module-types//', include(get_model_urls('dcim', 'moduletype'))), - # Console port templates - path('console-port-templates/add/', views.ConsolePortTemplateCreateView.as_view(), name='consoleporttemplate_add'), - path('console-port-templates/edit/', views.ConsolePortTemplateBulkEditView.as_view(), name='consoleporttemplate_bulk_edit'), - path('console-port-templates/rename/', views.ConsolePortTemplateBulkRenameView.as_view(), name='consoleporttemplate_bulk_rename'), - path('console-port-templates/delete/', views.ConsolePortTemplateBulkDeleteView.as_view(), name='consoleporttemplate_bulk_delete'), + path('console-port-templates/', include(get_model_urls('dcim', 'consoleporttemplate', detail=False))), path('console-port-templates//', include(get_model_urls('dcim', 'consoleporttemplate'))), - # Console server port templates - path('console-server-port-templates/add/', views.ConsoleServerPortTemplateCreateView.as_view(), name='consoleserverporttemplate_add'), - path('console-server-port-templates/edit/', views.ConsoleServerPortTemplateBulkEditView.as_view(), name='consoleserverporttemplate_bulk_edit'), - path('console-server-port-templates/rename/', views.ConsoleServerPortTemplateBulkRenameView.as_view(), name='consoleserverporttemplate_bulk_rename'), - path('console-server-port-templates/delete/', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='consoleserverporttemplate_bulk_delete'), + path('console-server-port-templates/', include(get_model_urls('dcim', 'consoleserverporttemplate', detail=False))), path('console-server-port-templates//', include(get_model_urls('dcim', 'consoleserverporttemplate'))), - # Power port templates - path('power-port-templates/add/', views.PowerPortTemplateCreateView.as_view(), name='powerporttemplate_add'), - path('power-port-templates/edit/', views.PowerPortTemplateBulkEditView.as_view(), name='powerporttemplate_bulk_edit'), - path('power-port-templates/rename/', views.PowerPortTemplateBulkRenameView.as_view(), name='powerporttemplate_bulk_rename'), - path('power-port-templates/delete/', views.PowerPortTemplateBulkDeleteView.as_view(), name='powerporttemplate_bulk_delete'), + path('power-port-templates/', include(get_model_urls('dcim', 'powerporttemplate', detail=False))), path('power-port-templates//', include(get_model_urls('dcim', 'powerporttemplate'))), - # Power outlet templates - path('power-outlet-templates/add/', views.PowerOutletTemplateCreateView.as_view(), name='poweroutlettemplate_add'), - path('power-outlet-templates/edit/', views.PowerOutletTemplateBulkEditView.as_view(), name='poweroutlettemplate_bulk_edit'), - path('power-outlet-templates/rename/', views.PowerOutletTemplateBulkRenameView.as_view(), name='poweroutlettemplate_bulk_rename'), - path('power-outlet-templates/delete/', views.PowerOutletTemplateBulkDeleteView.as_view(), name='poweroutlettemplate_bulk_delete'), + path('power-outlet-templates/', include(get_model_urls('dcim', 'poweroutlettemplate', detail=False))), path('power-outlet-templates//', include(get_model_urls('dcim', 'poweroutlettemplate'))), - # Interface templates - path('interface-templates/add/', views.InterfaceTemplateCreateView.as_view(), name='interfacetemplate_add'), - path('interface-templates/edit/', views.InterfaceTemplateBulkEditView.as_view(), name='interfacetemplate_bulk_edit'), - path('interface-templates/rename/', views.InterfaceTemplateBulkRenameView.as_view(), name='interfacetemplate_bulk_rename'), - path('interface-templates/delete/', views.InterfaceTemplateBulkDeleteView.as_view(), name='interfacetemplate_bulk_delete'), + path('interface-templates/', include(get_model_urls('dcim', 'interfacetemplate', detail=False))), path('interface-templates//', include(get_model_urls('dcim', 'interfacetemplate'))), - # Front port templates - path('front-port-templates/add/', views.FrontPortTemplateCreateView.as_view(), name='frontporttemplate_add'), - path('front-port-templates/edit/', views.FrontPortTemplateBulkEditView.as_view(), name='frontporttemplate_bulk_edit'), - path('front-port-templates/rename/', views.FrontPortTemplateBulkRenameView.as_view(), name='frontporttemplate_bulk_rename'), - path('front-port-templates/delete/', views.FrontPortTemplateBulkDeleteView.as_view(), name='frontporttemplate_bulk_delete'), + path('front-port-templates/', include(get_model_urls('dcim', 'frontporttemplate', detail=False))), path('front-port-templates//', include(get_model_urls('dcim', 'frontporttemplate'))), - # Rear port templates - path('rear-port-templates/add/', views.RearPortTemplateCreateView.as_view(), name='rearporttemplate_add'), - path('rear-port-templates/edit/', views.RearPortTemplateBulkEditView.as_view(), name='rearporttemplate_bulk_edit'), - path('rear-port-templates/rename/', views.RearPortTemplateBulkRenameView.as_view(), name='rearporttemplate_bulk_rename'), - path('rear-port-templates/delete/', views.RearPortTemplateBulkDeleteView.as_view(), name='rearporttemplate_bulk_delete'), + path('rear-port-templates/', include(get_model_urls('dcim', 'rearporttemplate', detail=False))), path('rear-port-templates//', include(get_model_urls('dcim', 'rearporttemplate'))), - # Device bay templates - path('device-bay-templates/add/', views.DeviceBayTemplateCreateView.as_view(), name='devicebaytemplate_add'), - path('device-bay-templates/edit/', views.DeviceBayTemplateBulkEditView.as_view(), name='devicebaytemplate_bulk_edit'), - path('device-bay-templates/rename/', views.DeviceBayTemplateBulkRenameView.as_view(), name='devicebaytemplate_bulk_rename'), - path('device-bay-templates/delete/', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicebaytemplate_bulk_delete'), + path('device-bay-templates/', include(get_model_urls('dcim', 'devicebaytemplate', detail=False))), path('device-bay-templates//', include(get_model_urls('dcim', 'devicebaytemplate'))), - # Module bay templates - path('module-bay-templates/add/', views.ModuleBayTemplateCreateView.as_view(), name='modulebaytemplate_add'), - path('module-bay-templates/edit/', views.ModuleBayTemplateBulkEditView.as_view(), name='modulebaytemplate_bulk_edit'), - path('module-bay-templates/rename/', views.ModuleBayTemplateBulkRenameView.as_view(), name='modulebaytemplate_bulk_rename'), - path('module-bay-templates/delete/', views.ModuleBayTemplateBulkDeleteView.as_view(), name='modulebaytemplate_bulk_delete'), + path('module-bay-templates/', include(get_model_urls('dcim', 'modulebaytemplate', detail=False))), path('module-bay-templates//', include(get_model_urls('dcim', 'modulebaytemplate'))), - # Inventory item templates - path('inventory-item-templates/add/', views.InventoryItemTemplateCreateView.as_view(), name='inventoryitemtemplate_add'), - path('inventory-item-templates/edit/', views.InventoryItemTemplateBulkEditView.as_view(), name='inventoryitemtemplate_bulk_edit'), - path('inventory-item-templates/rename/', views.InventoryItemTemplateBulkRenameView.as_view(), name='inventoryitemtemplate_bulk_rename'), - path('inventory-item-templates/delete/', views.InventoryItemTemplateBulkDeleteView.as_view(), name='inventoryitemtemplate_bulk_delete'), + path('inventory-item-templates/', include(get_model_urls('dcim', 'inventoryitemtemplate', detail=False))), path('inventory-item-templates//', include(get_model_urls('dcim', 'inventoryitemtemplate'))), - # Device roles - path('device-roles/', views.DeviceRoleListView.as_view(), name='devicerole_list'), - path('device-roles/add/', views.DeviceRoleEditView.as_view(), name='devicerole_add'), - path('device-roles/import/', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'), - path('device-roles/edit/', views.DeviceRoleBulkEditView.as_view(), name='devicerole_bulk_edit'), - path('device-roles/delete/', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'), + path('device-roles/', include(get_model_urls('dcim', 'devicerole', detail=False))), path('device-roles//', include(get_model_urls('dcim', 'devicerole'))), - # Platforms - path('platforms/', views.PlatformListView.as_view(), name='platform_list'), - path('platforms/add/', views.PlatformEditView.as_view(), name='platform_add'), - path('platforms/import/', views.PlatformBulkImportView.as_view(), name='platform_import'), - path('platforms/edit/', views.PlatformBulkEditView.as_view(), name='platform_bulk_edit'), - path('platforms/delete/', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'), + path('platforms/', include(get_model_urls('dcim', 'platform', detail=False))), path('platforms//', include(get_model_urls('dcim', 'platform'))), - # Devices - path('devices/', views.DeviceListView.as_view(), name='device_list'), - path('devices/add/', views.DeviceEditView.as_view(), name='device_add'), - path('devices/import/', views.DeviceBulkImportView.as_view(), name='device_import'), - path('devices/edit/', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'), - path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'), - path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'), + path('devices/', include(get_model_urls('dcim', 'device', detail=False))), path('devices//', include(get_model_urls('dcim', 'device'))), - # Virtual Device Context - path('virtual-device-contexts/', views.VirtualDeviceContextListView.as_view(), name='virtualdevicecontext_list'), - path('virtual-device-contexts/add/', views.VirtualDeviceContextEditView.as_view(), name='virtualdevicecontext_add'), - path('virtual-device-contexts/import/', views.VirtualDeviceContextBulkImportView.as_view(), name='virtualdevicecontext_import'), - path('virtual-device-contexts/edit/', views.VirtualDeviceContextBulkEditView.as_view(), name='virtualdevicecontext_bulk_edit'), - path('virtual-device-contexts/delete/', views.VirtualDeviceContextBulkDeleteView.as_view(), name='virtualdevicecontext_bulk_delete'), + path('virtual-device-contexts/', include(get_model_urls('dcim', 'virtualdevicecontext', detail=False))), path('virtual-device-contexts//', include(get_model_urls('dcim', 'virtualdevicecontext'))), - # Modules - path('modules/', views.ModuleListView.as_view(), name='module_list'), - path('modules/add/', views.ModuleEditView.as_view(), name='module_add'), - path('modules/import/', views.ModuleBulkImportView.as_view(), name='module_import'), - path('modules/edit/', views.ModuleBulkEditView.as_view(), name='module_bulk_edit'), - path('modules/delete/', views.ModuleBulkDeleteView.as_view(), name='module_bulk_delete'), + path('modules/', include(get_model_urls('dcim', 'module', detail=False))), path('modules//', include(get_model_urls('dcim', 'module'))), - # Console ports - path('console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'), - path('console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'), - path('console-ports/import/', views.ConsolePortBulkImportView.as_view(), name='consoleport_import'), - path('console-ports/edit/', views.ConsolePortBulkEditView.as_view(), name='consoleport_bulk_edit'), - path('console-ports/rename/', views.ConsolePortBulkRenameView.as_view(), name='consoleport_bulk_rename'), - path('console-ports/disconnect/', views.ConsolePortBulkDisconnectView.as_view(), name='consoleport_bulk_disconnect'), - path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'), + path('console-ports/', include(get_model_urls('dcim', 'consoleport', detail=False))), path('console-ports//', include(get_model_urls('dcim', 'consoleport'))), - path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'), + path( + 'devices/console-ports/add/', + views.DeviceBulkAddConsolePortView.as_view(), + name='device_bulk_add_consoleport' + ), - # Console server ports - path('console-server-ports/', views.ConsoleServerPortListView.as_view(), name='consoleserverport_list'), - path('console-server-ports/add/', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'), - path('console-server-ports/import/', views.ConsoleServerPortBulkImportView.as_view(), name='consoleserverport_import'), - path('console-server-ports/edit/', views.ConsoleServerPortBulkEditView.as_view(), name='consoleserverport_bulk_edit'), - path('console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'), - path('console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'), - path('console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'), + path('console-server-ports/', include(get_model_urls('dcim', 'consoleserverport', detail=False))), path('console-server-ports//', include(get_model_urls('dcim', 'consoleserverport'))), - path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'), + path( + 'devices/console-server-ports/add/', + views.DeviceBulkAddConsoleServerPortView.as_view(), + name='device_bulk_add_consoleserverport' + ), - # Power ports - path('power-ports/', views.PowerPortListView.as_view(), name='powerport_list'), - path('power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'), - path('power-ports/import/', views.PowerPortBulkImportView.as_view(), name='powerport_import'), - path('power-ports/edit/', views.PowerPortBulkEditView.as_view(), name='powerport_bulk_edit'), - path('power-ports/rename/', views.PowerPortBulkRenameView.as_view(), name='powerport_bulk_rename'), - path('power-ports/disconnect/', views.PowerPortBulkDisconnectView.as_view(), name='powerport_bulk_disconnect'), - path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'), + path('power-ports/', include(get_model_urls('dcim', 'powerport', detail=False))), path('power-ports//', include(get_model_urls('dcim', 'powerport'))), path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'), - # Power outlets - path('power-outlets/', views.PowerOutletListView.as_view(), name='poweroutlet_list'), - path('power-outlets/add/', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'), - path('power-outlets/import/', views.PowerOutletBulkImportView.as_view(), name='poweroutlet_import'), - path('power-outlets/edit/', views.PowerOutletBulkEditView.as_view(), name='poweroutlet_bulk_edit'), - path('power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'), - path('power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'), - path('power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'), + path('power-outlets/', include(get_model_urls('dcim', 'poweroutlet', detail=False))), path('power-outlets//', include(get_model_urls('dcim', 'poweroutlet'))), - path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'), + path( + 'devices/power-outlets/add/', + views.DeviceBulkAddPowerOutletView.as_view(), + name='device_bulk_add_poweroutlet' + ), - # Interfaces - path('interfaces/', views.InterfaceListView.as_view(), name='interface_list'), - path('interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'), - path('interfaces/import/', views.InterfaceBulkImportView.as_view(), name='interface_import'), - path('interfaces/edit/', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'), - path('interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'), - path('interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'), - path('interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'), + path('interfaces/', include(get_model_urls('dcim', 'interface', detail=False))), path('interfaces//', include(get_model_urls('dcim', 'interface'))), path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'), - # Front ports - path('front-ports/', views.FrontPortListView.as_view(), name='frontport_list'), - path('front-ports/add/', views.FrontPortCreateView.as_view(), name='frontport_add'), - path('front-ports/import/', views.FrontPortBulkImportView.as_view(), name='frontport_import'), - path('front-ports/edit/', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'), - path('front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'), - path('front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'), - path('front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'), + path('front-ports/', include(get_model_urls('dcim', 'frontport', detail=False))), path('front-ports//', include(get_model_urls('dcim', 'frontport'))), - # path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'), - # Rear ports - path('rear-ports/', views.RearPortListView.as_view(), name='rearport_list'), - path('rear-ports/add/', views.RearPortCreateView.as_view(), name='rearport_add'), - path('rear-ports/import/', views.RearPortBulkImportView.as_view(), name='rearport_import'), - path('rear-ports/edit/', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'), - path('rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'), - path('rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'), - path('rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'), + path('rear-ports/', include(get_model_urls('dcim', 'rearport', detail=False))), path('rear-ports//', include(get_model_urls('dcim', 'rearport'))), path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'), - # Module bays - path('module-bays/', views.ModuleBayListView.as_view(), name='modulebay_list'), - path('module-bays/add/', views.ModuleBayCreateView.as_view(), name='modulebay_add'), - path('module-bays/import/', views.ModuleBayBulkImportView.as_view(), name='modulebay_import'), - path('module-bays/edit/', views.ModuleBayBulkEditView.as_view(), name='modulebay_bulk_edit'), - path('module-bays/rename/', views.ModuleBayBulkRenameView.as_view(), name='modulebay_bulk_rename'), - path('module-bays/delete/', views.ModuleBayBulkDeleteView.as_view(), name='modulebay_bulk_delete'), + path('module-bays/', include(get_model_urls('dcim', 'modulebay', detail=False))), path('module-bays//', include(get_model_urls('dcim', 'modulebay'))), path('devices/module-bays/add/', views.DeviceBulkAddModuleBayView.as_view(), name='device_bulk_add_modulebay'), - # Device bays - path('device-bays/', views.DeviceBayListView.as_view(), name='devicebay_list'), - path('device-bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'), - path('device-bays/import/', views.DeviceBayBulkImportView.as_view(), name='devicebay_import'), - path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'), - path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'), - path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'), + path('device-bays/', include(get_model_urls('dcim', 'devicebay', detail=False))), path('device-bays//', include(get_model_urls('dcim', 'devicebay'))), path('devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'), - # Inventory items - path('inventory-items/', views.InventoryItemListView.as_view(), name='inventoryitem_list'), - path('inventory-items/add/', views.InventoryItemCreateView.as_view(), name='inventoryitem_add'), - path('inventory-items/import/', views.InventoryItemBulkImportView.as_view(), name='inventoryitem_import'), - path('inventory-items/edit/', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'), - path('inventory-items/rename/', views.InventoryItemBulkRenameView.as_view(), name='inventoryitem_bulk_rename'), - path('inventory-items/delete/', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'), + path('inventory-items/', include(get_model_urls('dcim', 'inventoryitem', detail=False))), path('inventory-items//', include(get_model_urls('dcim', 'inventoryitem'))), - path('devices/inventory-items/add/', views.DeviceBulkAddInventoryItemView.as_view(), name='device_bulk_add_inventoryitem'), + path( + 'devices/inventory-items/add/', + views.DeviceBulkAddInventoryItemView.as_view(), + name='device_bulk_add_inventoryitem' + ), - # Inventory item roles - path('inventory-item-roles/', views.InventoryItemRoleListView.as_view(), name='inventoryitemrole_list'), - path('inventory-item-roles/add/', views.InventoryItemRoleEditView.as_view(), name='inventoryitemrole_add'), - path('inventory-item-roles/import/', views.InventoryItemRoleBulkImportView.as_view(), name='inventoryitemrole_import'), - path('inventory-item-roles/edit/', views.InventoryItemRoleBulkEditView.as_view(), name='inventoryitemrole_bulk_edit'), - path('inventory-item-roles/delete/', views.InventoryItemRoleBulkDeleteView.as_view(), name='inventoryitemrole_bulk_delete'), + path('inventory-item-roles/', include(get_model_urls('dcim', 'inventoryitemrole', detail=False))), path('inventory-item-roles//', include(get_model_urls('dcim', 'inventoryitemrole'))), - # Cables - path('cables/', views.CableListView.as_view(), name='cable_list'), - path('cables/add/', views.CableEditView.as_view(), name='cable_add'), - path('cables/import/', views.CableBulkImportView.as_view(), name='cable_import'), - path('cables/edit/', views.CableBulkEditView.as_view(), name='cable_bulk_edit'), - path('cables/delete/', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'), + path('cables/', include(get_model_urls('dcim', 'cable', detail=False))), path('cables//', include(get_model_urls('dcim', 'cable'))), # Console/power/interface connections (read-only) @@ -334,30 +151,21 @@ urlpatterns = [ path('power-connections/', views.PowerConnectionsListView.as_view(), name='power_connections_list'), path('interface-connections/', views.InterfaceConnectionsListView.as_view(), name='interface_connections_list'), - # Virtual chassis - path('virtual-chassis/', views.VirtualChassisListView.as_view(), name='virtualchassis_list'), - path('virtual-chassis/add/', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'), - path('virtual-chassis/import/', views.VirtualChassisBulkImportView.as_view(), name='virtualchassis_import'), - path('virtual-chassis/edit/', views.VirtualChassisBulkEditView.as_view(), name='virtualchassis_bulk_edit'), - path('virtual-chassis/delete/', views.VirtualChassisBulkDeleteView.as_view(), name='virtualchassis_bulk_delete'), + path('virtual-chassis/', include(get_model_urls('dcim', 'virtualchassis', detail=False))), path('virtual-chassis//', include(get_model_urls('dcim', 'virtualchassis'))), - path('virtual-chassis-members//delete/', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'), + path( + 'virtual-chassis-members//delete/', + views.VirtualChassisRemoveMemberView.as_view(), + name='virtualchassis_remove_member' + ), - # Power panels - path('power-panels/', views.PowerPanelListView.as_view(), name='powerpanel_list'), - path('power-panels/add/', views.PowerPanelEditView.as_view(), name='powerpanel_add'), - path('power-panels/import/', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'), - path('power-panels/edit/', views.PowerPanelBulkEditView.as_view(), name='powerpanel_bulk_edit'), - path('power-panels/delete/', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'), + path('power-panels/', include(get_model_urls('dcim', 'powerpanel', detail=False))), path('power-panels//', include(get_model_urls('dcim', 'powerpanel'))), - # Power feeds - path('power-feeds/', views.PowerFeedListView.as_view(), name='powerfeed_list'), - path('power-feeds/add/', views.PowerFeedEditView.as_view(), name='powerfeed_add'), - path('power-feeds/import/', views.PowerFeedBulkImportView.as_view(), name='powerfeed_import'), - path('power-feeds/edit/', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'), - path('power-feeds/disconnect/', views.PowerFeedBulkDisconnectView.as_view(), name='powerfeed_bulk_disconnect'), - path('power-feeds/delete/', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'), + path('power-feeds/', include(get_model_urls('dcim', 'powerfeed', detail=False))), path('power-feeds//', include(get_model_urls('dcim', 'powerfeed'))), + path('mac-addresses/', include(get_model_urls('dcim', 'macaddress', detail=False))), + path('mac-addresses//', include(get_model_urls('dcim', 'macaddress'))), + ] diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 7a5a771a9..731034dc1 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -35,7 +35,7 @@ from virtualization.forms import VirtualMachineFilterForm from virtualization.models import VirtualMachine from virtualization.tables import VirtualMachineTable from . import filtersets, forms, tables -from .choices import DeviceFaceChoices +from .choices import DeviceFaceChoices, InterfaceModeChoices from .models import * CABLE_TERMINATION_TYPES = { @@ -215,6 +215,7 @@ class PathTraceView(generic.ObjectView): # Regions # +@register_model_view(Region, 'list', path='', detail=False) class RegionListView(generic.ObjectListView): queryset = Region.objects.add_related_count( Region.objects.all(), @@ -243,7 +244,9 @@ class RegionView(GetRelatedModelsMixin, generic.ObjectView): (Location.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'), (Rack.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'), ( - Circuit.objects.restrict(request.user, 'view').filter(terminations___region=instance).distinct(), + Circuit.objects.restrict(request.user, 'view').filter( + terminations___region=instance + ).distinct(), 'region_id' ), ), @@ -251,6 +254,7 @@ class RegionView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Region, 'add', detail=False) @register_model_view(Region, 'edit') class RegionEditView(generic.ObjectEditView): queryset = Region.objects.all() @@ -262,11 +266,13 @@ class RegionDeleteView(generic.ObjectDeleteView): queryset = Region.objects.all() +@register_model_view(Region, 'import', detail=False) class RegionBulkImportView(generic.BulkImportView): queryset = Region.objects.all() model_form = forms.RegionImportForm +@register_model_view(Region, 'bulk_edit', path='edit', detail=False) class RegionBulkEditView(generic.BulkEditView): queryset = Region.objects.add_related_count( Region.objects.all(), @@ -280,6 +286,7 @@ class RegionBulkEditView(generic.BulkEditView): form = forms.RegionBulkEditForm +@register_model_view(Region, 'bulk_delete', path='delete', detail=False) class RegionBulkDeleteView(generic.BulkDeleteView): queryset = Region.objects.add_related_count( Region.objects.all(), @@ -301,6 +308,7 @@ class RegionContactsView(ObjectContactsView): # Site groups # +@register_model_view(SiteGroup, 'list', path='', detail=False) class SiteGroupListView(generic.ObjectListView): queryset = SiteGroup.objects.add_related_count( SiteGroup.objects.all(), @@ -329,7 +337,9 @@ class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView): (Location.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'), (Rack.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'), ( - Circuit.objects.restrict(request.user, 'view').filter(terminations___site_group=instance).distinct(), + Circuit.objects.restrict(request.user, 'view').filter( + terminations___site_group=instance + ).distinct(), 'site_group_id' ), ), @@ -337,6 +347,7 @@ class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(SiteGroup, 'add', detail=False) @register_model_view(SiteGroup, 'edit') class SiteGroupEditView(generic.ObjectEditView): queryset = SiteGroup.objects.all() @@ -348,11 +359,13 @@ class SiteGroupDeleteView(generic.ObjectDeleteView): queryset = SiteGroup.objects.all() +@register_model_view(SiteGroup, 'import', detail=False) class SiteGroupBulkImportView(generic.BulkImportView): queryset = SiteGroup.objects.all() model_form = forms.SiteGroupImportForm +@register_model_view(SiteGroup, 'bulk_edit', path='edit', detail=False) class SiteGroupBulkEditView(generic.BulkEditView): queryset = SiteGroup.objects.add_related_count( SiteGroup.objects.all(), @@ -366,6 +379,7 @@ class SiteGroupBulkEditView(generic.BulkEditView): form = forms.SiteGroupBulkEditForm +@register_model_view(SiteGroup, 'bulk_delete', path='delete', detail=False) class SiteGroupBulkDeleteView(generic.BulkDeleteView): queryset = SiteGroup.objects.add_related_count( SiteGroup.objects.all(), @@ -387,6 +401,7 @@ class SiteGroupContactsView(ObjectContactsView): # Sites # +@register_model_view(Site, 'list', path='', detail=False) class SiteListView(generic.ObjectListView): queryset = Site.objects.annotate( device_count=count_related(Device, 'site') @@ -421,6 +436,7 @@ class SiteView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Site, 'add', detail=False) @register_model_view(Site, 'edit') class SiteEditView(generic.ObjectEditView): queryset = Site.objects.all() @@ -432,11 +448,13 @@ class SiteDeleteView(generic.ObjectDeleteView): queryset = Site.objects.all() +@register_model_view(Site, 'import', detail=False) class SiteBulkImportView(generic.BulkImportView): queryset = Site.objects.all() model_form = forms.SiteImportForm +@register_model_view(Site, 'bulk_edit', path='edit', detail=False) class SiteBulkEditView(generic.BulkEditView): queryset = Site.objects.all() filterset = filtersets.SiteFilterSet @@ -444,6 +462,7 @@ class SiteBulkEditView(generic.BulkEditView): form = forms.SiteBulkEditForm +@register_model_view(Site, 'bulk_delete', path='delete', detail=False) class SiteBulkDeleteView(generic.BulkDeleteView): queryset = Site.objects.all() filterset = filtersets.SiteFilterSet @@ -459,6 +478,7 @@ class SiteContactsView(ObjectContactsView): # Locations # +@register_model_view(Location, 'list', path='', detail=False) class LocationListView(generic.ObjectListView): queryset = Location.objects.add_related_count( Location.objects.add_related_count( @@ -491,7 +511,9 @@ class LocationView(GetRelatedModelsMixin, generic.ObjectView): [CableTermination], ( ( - Circuit.objects.restrict(request.user, 'view').filter(terminations___location=instance).distinct(), + Circuit.objects.restrict(request.user, 'view').filter( + terminations___location=instance + ).distinct(), 'location_id' ), ), @@ -499,6 +521,7 @@ class LocationView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Location, 'add', detail=False) @register_model_view(Location, 'edit') class LocationEditView(generic.ObjectEditView): queryset = Location.objects.all() @@ -510,11 +533,13 @@ class LocationDeleteView(generic.ObjectDeleteView): queryset = Location.objects.all() +@register_model_view(Location, 'import', detail=False) class LocationBulkImportView(generic.BulkImportView): queryset = Location.objects.all() model_form = forms.LocationImportForm +@register_model_view(Location, 'bulk_edit', path='edit', detail=False) class LocationBulkEditView(generic.BulkEditView): queryset = Location.objects.add_related_count( Location.objects.all(), @@ -528,6 +553,7 @@ class LocationBulkEditView(generic.BulkEditView): form = forms.LocationBulkEditForm +@register_model_view(Location, 'bulk_delete', path='delete', detail=False) class LocationBulkDeleteView(generic.BulkDeleteView): queryset = Location.objects.add_related_count( Location.objects.all(), @@ -549,6 +575,7 @@ class LocationContactsView(ObjectContactsView): # Rack roles # +@register_model_view(RackRole, 'list', path='', detail=False) class RackRoleListView(generic.ObjectListView): queryset = RackRole.objects.annotate( rack_count=count_related(Rack, 'role') @@ -568,6 +595,7 @@ class RackRoleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(RackRole, 'add', detail=False) @register_model_view(RackRole, 'edit') class RackRoleEditView(generic.ObjectEditView): queryset = RackRole.objects.all() @@ -579,11 +607,13 @@ class RackRoleDeleteView(generic.ObjectDeleteView): queryset = RackRole.objects.all() +@register_model_view(RackRole, 'import', detail=False) class RackRoleBulkImportView(generic.BulkImportView): queryset = RackRole.objects.all() model_form = forms.RackRoleImportForm +@register_model_view(RackRole, 'bulk_edit', path='edit', detail=False) class RackRoleBulkEditView(generic.BulkEditView): queryset = RackRole.objects.annotate( rack_count=count_related(Rack, 'role') @@ -593,6 +623,7 @@ class RackRoleBulkEditView(generic.BulkEditView): form = forms.RackRoleBulkEditForm +@register_model_view(RackRole, 'bulk_delete', path='delete', detail=False) class RackRoleBulkDeleteView(generic.BulkDeleteView): queryset = RackRole.objects.annotate( rack_count=count_related(Rack, 'role') @@ -605,6 +636,7 @@ class RackRoleBulkDeleteView(generic.BulkDeleteView): # RackTypes # +@register_model_view(RackType, 'list', path='', detail=False) class RackTypeListView(generic.ObjectListView): queryset = RackType.objects.annotate( instance_count=count_related(Rack, 'rack_type') @@ -624,6 +656,7 @@ class RackTypeView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(RackType, 'add', detail=False) @register_model_view(RackType, 'edit') class RackTypeEditView(generic.ObjectEditView): queryset = RackType.objects.all() @@ -635,11 +668,13 @@ class RackTypeDeleteView(generic.ObjectDeleteView): queryset = RackType.objects.all() +@register_model_view(RackType, 'import', detail=False) class RackTypeBulkImportView(generic.BulkImportView): queryset = RackType.objects.all() model_form = forms.RackTypeImportForm +@register_model_view(RackType, 'bulk_edit', path='edit', detail=False) class RackTypeBulkEditView(generic.BulkEditView): queryset = RackType.objects.all() filterset = filtersets.RackTypeFilterSet @@ -647,6 +682,7 @@ class RackTypeBulkEditView(generic.BulkEditView): form = forms.RackTypeBulkEditForm +@register_model_view(RackType, 'bulk_delete', path='delete', detail=False) class RackTypeBulkDeleteView(generic.BulkDeleteView): queryset = RackType.objects.all() filterset = filtersets.RackTypeFilterSet @@ -657,6 +693,7 @@ class RackTypeBulkDeleteView(generic.BulkDeleteView): # Racks # +@register_model_view(Rack, 'list', path='', detail=False) class RackListView(generic.ObjectListView): queryset = Rack.objects.annotate( device_count=count_related(Device, 'rack') @@ -787,6 +824,7 @@ class RackNonRackedView(generic.ObjectChildrenView): ) +@register_model_view(Rack, 'add', detail=False) @register_model_view(Rack, 'edit') class RackEditView(generic.ObjectEditView): queryset = Rack.objects.all() @@ -798,11 +836,13 @@ class RackDeleteView(generic.ObjectDeleteView): queryset = Rack.objects.all() +@register_model_view(Rack, 'import', detail=False) class RackBulkImportView(generic.BulkImportView): queryset = Rack.objects.all() model_form = forms.RackImportForm +@register_model_view(Rack, 'bulk_edit', path='edit', detail=False) class RackBulkEditView(generic.BulkEditView): queryset = Rack.objects.all() filterset = filtersets.RackFilterSet @@ -810,6 +850,7 @@ class RackBulkEditView(generic.BulkEditView): form = forms.RackBulkEditForm +@register_model_view(Rack, 'bulk_delete', path='delete', detail=False) class RackBulkDeleteView(generic.BulkDeleteView): queryset = Rack.objects.all() filterset = filtersets.RackFilterSet @@ -825,6 +866,7 @@ class RackContactsView(ObjectContactsView): # Rack reservations # +@register_model_view(RackReservation, 'list', path='', detail=False) class RackReservationListView(generic.ObjectListView): queryset = RackReservation.objects.all() filterset = filtersets.RackReservationFilterSet @@ -837,6 +879,7 @@ class RackReservationView(generic.ObjectView): queryset = RackReservation.objects.all() +@register_model_view(RackReservation, 'add', detail=False) @register_model_view(RackReservation, 'edit') class RackReservationEditView(generic.ObjectEditView): queryset = RackReservation.objects.all() @@ -855,6 +898,7 @@ class RackReservationDeleteView(generic.ObjectDeleteView): queryset = RackReservation.objects.all() +@register_model_view(RackReservation, 'import', detail=False) class RackReservationImportView(generic.BulkImportView): queryset = RackReservation.objects.all() model_form = forms.RackReservationImportForm @@ -870,6 +914,7 @@ class RackReservationImportView(generic.BulkImportView): return instance +@register_model_view(RackReservation, 'bulk_edit', path='edit', detail=False) class RackReservationBulkEditView(generic.BulkEditView): queryset = RackReservation.objects.all() filterset = filtersets.RackReservationFilterSet @@ -877,6 +922,7 @@ class RackReservationBulkEditView(generic.BulkEditView): form = forms.RackReservationBulkEditForm +@register_model_view(RackReservation, 'bulk_delete', path='delete', detail=False) class RackReservationBulkDeleteView(generic.BulkDeleteView): queryset = RackReservation.objects.all() filterset = filtersets.RackReservationFilterSet @@ -887,6 +933,7 @@ class RackReservationBulkDeleteView(generic.BulkDeleteView): # Manufacturers # +@register_model_view(Manufacturer, 'list', path='', detail=False) class ManufacturerListView(generic.ObjectListView): queryset = Manufacturer.objects.annotate( devicetype_count=count_related(DeviceType, 'manufacturer'), @@ -909,6 +956,7 @@ class ManufacturerView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Manufacturer, 'add', detail=False) @register_model_view(Manufacturer, 'edit') class ManufacturerEditView(generic.ObjectEditView): queryset = Manufacturer.objects.all() @@ -920,11 +968,13 @@ class ManufacturerDeleteView(generic.ObjectDeleteView): queryset = Manufacturer.objects.all() +@register_model_view(Manufacturer, 'import', detail=False) class ManufacturerBulkImportView(generic.BulkImportView): queryset = Manufacturer.objects.all() model_form = forms.ManufacturerImportForm +@register_model_view(Manufacturer, 'bulk_edit', path='edit', detail=False) class ManufacturerBulkEditView(generic.BulkEditView): queryset = Manufacturer.objects.annotate( devicetype_count=count_related(DeviceType, 'manufacturer'), @@ -937,6 +987,7 @@ class ManufacturerBulkEditView(generic.BulkEditView): form = forms.ManufacturerBulkEditForm +@register_model_view(Manufacturer, 'bulk_delete', path='delete', detail=False) class ManufacturerBulkDeleteView(generic.BulkDeleteView): queryset = Manufacturer.objects.annotate( devicetype_count=count_related(DeviceType, 'manufacturer'), @@ -957,6 +1008,7 @@ class ManufacturerContactsView(ObjectContactsView): # Device types # +@register_model_view(DeviceType, 'list', path='', detail=False) class DeviceTypeListView(generic.ObjectListView): queryset = DeviceType.objects.annotate( instance_count=count_related(Device, 'device_type') @@ -980,6 +1032,7 @@ class DeviceTypeView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(DeviceType, 'add', detail=False) @register_model_view(DeviceType, 'edit') class DeviceTypeEditView(generic.ObjectEditView): queryset = DeviceType.objects.all() @@ -1141,6 +1194,7 @@ class DeviceTypeInventoryItemsView(DeviceTypeComponentsView): ) +@register_model_view(DeviceType, 'import', detail=False) class DeviceTypeImportView(generic.BulkImportView): additional_permissions = [ 'dcim.add_devicetype', @@ -1175,6 +1229,7 @@ class DeviceTypeImportView(generic.BulkImportView): return data +@register_model_view(DeviceType, 'bulk_edit', path='edit', detail=False) class DeviceTypeBulkEditView(generic.BulkEditView): queryset = DeviceType.objects.annotate( instance_count=count_related(Device, 'device_type') @@ -1184,6 +1239,7 @@ class DeviceTypeBulkEditView(generic.BulkEditView): form = forms.DeviceTypeBulkEditForm +@register_model_view(DeviceType, 'bulk_delete', path='delete', detail=False) class DeviceTypeBulkDeleteView(generic.BulkDeleteView): queryset = DeviceType.objects.annotate( instance_count=count_related(Device, 'device_type') @@ -1196,6 +1252,7 @@ class DeviceTypeBulkDeleteView(generic.BulkDeleteView): # Module types # +@register_model_view(ModuleType, 'list', path='', detail=False) class ModuleTypeListView(generic.ObjectListView): queryset = ModuleType.objects.annotate( instance_count=count_related(Module, 'module_type') @@ -1219,6 +1276,7 @@ class ModuleTypeView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ModuleType, 'add', detail=False) @register_model_view(ModuleType, 'edit') class ModuleTypeEditView(generic.ObjectEditView): queryset = ModuleType.objects.all() @@ -1350,6 +1408,7 @@ class ModuleTypeModuleBaysView(ModuleTypeComponentsView): ) +@register_model_view(ModuleType, 'import', detail=False) class ModuleTypeImportView(generic.BulkImportView): additional_permissions = [ 'dcim.add_moduletype', @@ -1378,6 +1437,7 @@ class ModuleTypeImportView(generic.BulkImportView): return data +@register_model_view(ModuleType, 'bulk_edit', path='edit', detail=False) class ModuleTypeBulkEditView(generic.BulkEditView): queryset = ModuleType.objects.annotate( instance_count=count_related(Module, 'module_type') @@ -1387,6 +1447,7 @@ class ModuleTypeBulkEditView(generic.BulkEditView): form = forms.ModuleTypeBulkEditForm +@register_model_view(ModuleType, 'bulk_delete', path='delete', detail=False) class ModuleTypeBulkDeleteView(generic.BulkDeleteView): queryset = ModuleType.objects.annotate( instance_count=count_related(Module, 'module_type') @@ -1399,6 +1460,7 @@ class ModuleTypeBulkDeleteView(generic.BulkDeleteView): # Console port templates # +@register_model_view(ConsolePortTemplate, 'add', detail=False) class ConsolePortTemplateCreateView(generic.ComponentCreateView): queryset = ConsolePortTemplate.objects.all() form = forms.ConsolePortTemplateCreateForm @@ -1416,16 +1478,19 @@ class ConsolePortTemplateDeleteView(generic.ObjectDeleteView): queryset = ConsolePortTemplate.objects.all() +@register_model_view(ConsolePortTemplate, 'bulk_edit', path='edit', detail=False) class ConsolePortTemplateBulkEditView(generic.BulkEditView): queryset = ConsolePortTemplate.objects.all() table = tables.ConsolePortTemplateTable form = forms.ConsolePortTemplateBulkEditForm +@register_model_view(ConsolePortTemplate, 'bulk_rename', path='rename', detail=False) class ConsolePortTemplateBulkRenameView(generic.BulkRenameView): queryset = ConsolePortTemplate.objects.all() +@register_model_view(ConsolePortTemplate, 'bulk_delete', path='delete', detail=False) class ConsolePortTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ConsolePortTemplate.objects.all() table = tables.ConsolePortTemplateTable @@ -1435,6 +1500,7 @@ class ConsolePortTemplateBulkDeleteView(generic.BulkDeleteView): # Console server port templates # +@register_model_view(ConsoleServerPortTemplate, 'add', detail=False) class ConsoleServerPortTemplateCreateView(generic.ComponentCreateView): queryset = ConsoleServerPortTemplate.objects.all() form = forms.ConsoleServerPortTemplateCreateForm @@ -1452,16 +1518,19 @@ class ConsoleServerPortTemplateDeleteView(generic.ObjectDeleteView): queryset = ConsoleServerPortTemplate.objects.all() +@register_model_view(ConsoleServerPortTemplate, 'bulk_edit', path='edit', detail=False) class ConsoleServerPortTemplateBulkEditView(generic.BulkEditView): queryset = ConsoleServerPortTemplate.objects.all() table = tables.ConsoleServerPortTemplateTable form = forms.ConsoleServerPortTemplateBulkEditForm +@register_model_view(ConsoleServerPortTemplate, 'bulk_rename', detail=False) class ConsoleServerPortTemplateBulkRenameView(generic.BulkRenameView): queryset = ConsoleServerPortTemplate.objects.all() +@register_model_view(ConsoleServerPortTemplate, 'bulk_delete', path='delete', detail=False) class ConsoleServerPortTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ConsoleServerPortTemplate.objects.all() table = tables.ConsoleServerPortTemplateTable @@ -1471,6 +1540,7 @@ class ConsoleServerPortTemplateBulkDeleteView(generic.BulkDeleteView): # Power port templates # +@register_model_view(PowerPortTemplate, 'add', detail=False) class PowerPortTemplateCreateView(generic.ComponentCreateView): queryset = PowerPortTemplate.objects.all() form = forms.PowerPortTemplateCreateForm @@ -1488,16 +1558,19 @@ class PowerPortTemplateDeleteView(generic.ObjectDeleteView): queryset = PowerPortTemplate.objects.all() +@register_model_view(PowerPortTemplate, 'bulk_edit', path='edit', detail=False) class PowerPortTemplateBulkEditView(generic.BulkEditView): queryset = PowerPortTemplate.objects.all() table = tables.PowerPortTemplateTable form = forms.PowerPortTemplateBulkEditForm +@register_model_view(PowerPortTemplate, 'bulk_rename', path='rename', detail=False) class PowerPortTemplateBulkRenameView(generic.BulkRenameView): queryset = PowerPortTemplate.objects.all() +@register_model_view(PowerPortTemplate, 'bulk_delete', path='delete', detail=False) class PowerPortTemplateBulkDeleteView(generic.BulkDeleteView): queryset = PowerPortTemplate.objects.all() table = tables.PowerPortTemplateTable @@ -1507,6 +1580,7 @@ class PowerPortTemplateBulkDeleteView(generic.BulkDeleteView): # Power outlet templates # +@register_model_view(PowerOutletTemplate, 'add', detail=False) class PowerOutletTemplateCreateView(generic.ComponentCreateView): queryset = PowerOutletTemplate.objects.all() form = forms.PowerOutletTemplateCreateForm @@ -1524,16 +1598,19 @@ class PowerOutletTemplateDeleteView(generic.ObjectDeleteView): queryset = PowerOutletTemplate.objects.all() +@register_model_view(PowerOutletTemplate, 'bulk_edit', path='edit', detail=False) class PowerOutletTemplateBulkEditView(generic.BulkEditView): queryset = PowerOutletTemplate.objects.all() table = tables.PowerOutletTemplateTable form = forms.PowerOutletTemplateBulkEditForm +@register_model_view(PowerOutletTemplate, 'bulk_rename', path='rename', detail=False) class PowerOutletTemplateBulkRenameView(generic.BulkRenameView): queryset = PowerOutletTemplate.objects.all() +@register_model_view(PowerOutletTemplate, 'bulk_delete', path='delete', detail=False) class PowerOutletTemplateBulkDeleteView(generic.BulkDeleteView): queryset = PowerOutletTemplate.objects.all() table = tables.PowerOutletTemplateTable @@ -1543,6 +1620,7 @@ class PowerOutletTemplateBulkDeleteView(generic.BulkDeleteView): # Interface templates # +@register_model_view(InterfaceTemplate, 'add', detail=False) class InterfaceTemplateCreateView(generic.ComponentCreateView): queryset = InterfaceTemplate.objects.all() form = forms.InterfaceTemplateCreateForm @@ -1560,16 +1638,19 @@ class InterfaceTemplateDeleteView(generic.ObjectDeleteView): queryset = InterfaceTemplate.objects.all() +@register_model_view(InterfaceTemplate, 'bulk_edit', path='edit', detail=False) class InterfaceTemplateBulkEditView(generic.BulkEditView): queryset = InterfaceTemplate.objects.all() table = tables.InterfaceTemplateTable form = forms.InterfaceTemplateBulkEditForm +@register_model_view(InterfaceTemplate, 'bulk_rename', path='rename', detail=False) class InterfaceTemplateBulkRenameView(generic.BulkRenameView): queryset = InterfaceTemplate.objects.all() +@register_model_view(InterfaceTemplate, 'bulk_delete', path='delete', detail=False) class InterfaceTemplateBulkDeleteView(generic.BulkDeleteView): queryset = InterfaceTemplate.objects.all() table = tables.InterfaceTemplateTable @@ -1579,6 +1660,7 @@ class InterfaceTemplateBulkDeleteView(generic.BulkDeleteView): # Front port templates # +@register_model_view(FrontPortTemplate, 'add', detail=False) class FrontPortTemplateCreateView(generic.ComponentCreateView): queryset = FrontPortTemplate.objects.all() form = forms.FrontPortTemplateCreateForm @@ -1596,16 +1678,19 @@ class FrontPortTemplateDeleteView(generic.ObjectDeleteView): queryset = FrontPortTemplate.objects.all() +@register_model_view(FrontPortTemplate, 'bulk_edit', path='edit', detail=False) class FrontPortTemplateBulkEditView(generic.BulkEditView): queryset = FrontPortTemplate.objects.all() table = tables.FrontPortTemplateTable form = forms.FrontPortTemplateBulkEditForm +@register_model_view(FrontPortTemplate, 'bulk_rename', path='rename', detail=False) class FrontPortTemplateBulkRenameView(generic.BulkRenameView): queryset = FrontPortTemplate.objects.all() +@register_model_view(FrontPortTemplate, 'bulk_delete', path='delete', detail=False) class FrontPortTemplateBulkDeleteView(generic.BulkDeleteView): queryset = FrontPortTemplate.objects.all() table = tables.FrontPortTemplateTable @@ -1615,6 +1700,7 @@ class FrontPortTemplateBulkDeleteView(generic.BulkDeleteView): # Rear port templates # +@register_model_view(RearPortTemplate, 'add', detail=False) class RearPortTemplateCreateView(generic.ComponentCreateView): queryset = RearPortTemplate.objects.all() form = forms.RearPortTemplateCreateForm @@ -1632,16 +1718,19 @@ class RearPortTemplateDeleteView(generic.ObjectDeleteView): queryset = RearPortTemplate.objects.all() +@register_model_view(RearPortTemplate, 'bulk_edit', path='edit', detail=False) class RearPortTemplateBulkEditView(generic.BulkEditView): queryset = RearPortTemplate.objects.all() table = tables.RearPortTemplateTable form = forms.RearPortTemplateBulkEditForm +@register_model_view(RearPortTemplate, 'bulk_rename', path='rename', detail=False) class RearPortTemplateBulkRenameView(generic.BulkRenameView): queryset = RearPortTemplate.objects.all() +@register_model_view(RearPortTemplate, 'bulk_delete', path='delete', detail=False) class RearPortTemplateBulkDeleteView(generic.BulkDeleteView): queryset = RearPortTemplate.objects.all() table = tables.RearPortTemplateTable @@ -1651,6 +1740,7 @@ class RearPortTemplateBulkDeleteView(generic.BulkDeleteView): # Module bay templates # +@register_model_view(ModuleBayTemplate, 'add', detail=False) class ModuleBayTemplateCreateView(generic.ComponentCreateView): queryset = ModuleBayTemplate.objects.all() form = forms.ModuleBayTemplateCreateForm @@ -1668,16 +1758,19 @@ class ModuleBayTemplateDeleteView(generic.ObjectDeleteView): queryset = ModuleBayTemplate.objects.all() +@register_model_view(ModuleBayTemplate, 'bulk_edit', path='edit', detail=False) class ModuleBayTemplateBulkEditView(generic.BulkEditView): queryset = ModuleBayTemplate.objects.all() table = tables.ModuleBayTemplateTable form = forms.ModuleBayTemplateBulkEditForm +@register_model_view(ModuleBayTemplate, 'bulk_rename', path='rename', detail=False) class ModuleBayTemplateBulkRenameView(generic.BulkRenameView): queryset = ModuleBayTemplate.objects.all() +@register_model_view(ModuleBayTemplate, 'bulk_delete', path='delete', detail=False) class ModuleBayTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ModuleBayTemplate.objects.all() table = tables.ModuleBayTemplateTable @@ -1687,6 +1780,7 @@ class ModuleBayTemplateBulkDeleteView(generic.BulkDeleteView): # Device bay templates # +@register_model_view(DeviceBayTemplate, 'add', detail=False) class DeviceBayTemplateCreateView(generic.ComponentCreateView): queryset = DeviceBayTemplate.objects.all() form = forms.DeviceBayTemplateCreateForm @@ -1704,16 +1798,19 @@ class DeviceBayTemplateDeleteView(generic.ObjectDeleteView): queryset = DeviceBayTemplate.objects.all() +@register_model_view(DeviceBayTemplate, 'bulk_edit', path='edit', detail=False) class DeviceBayTemplateBulkEditView(generic.BulkEditView): queryset = DeviceBayTemplate.objects.all() table = tables.DeviceBayTemplateTable form = forms.DeviceBayTemplateBulkEditForm +@register_model_view(DeviceBayTemplate, 'bulk_rename', path='rename', detail=False) class DeviceBayTemplateBulkRenameView(generic.BulkRenameView): queryset = DeviceBayTemplate.objects.all() +@register_model_view(DeviceBayTemplate, 'bulk_delete', path='delete', detail=False) class DeviceBayTemplateBulkDeleteView(generic.BulkDeleteView): queryset = DeviceBayTemplate.objects.all() table = tables.DeviceBayTemplateTable @@ -1723,6 +1820,7 @@ class DeviceBayTemplateBulkDeleteView(generic.BulkDeleteView): # Inventory item templates # +@register_model_view(InventoryItemTemplate, 'add', detail=False) class InventoryItemTemplateCreateView(generic.ComponentCreateView): queryset = InventoryItemTemplate.objects.all() form = forms.InventoryItemTemplateCreateForm @@ -1751,16 +1849,19 @@ class InventoryItemTemplateDeleteView(generic.ObjectDeleteView): queryset = InventoryItemTemplate.objects.all() +@register_model_view(InventoryItemTemplate, 'bulk_edit', path='edit', detail=False) class InventoryItemTemplateBulkEditView(generic.BulkEditView): queryset = InventoryItemTemplate.objects.all() table = tables.InventoryItemTemplateTable form = forms.InventoryItemTemplateBulkEditForm +@register_model_view(InventoryItemTemplate, 'bulk_rename', path='rename', detail=False) class InventoryItemTemplateBulkRenameView(generic.BulkRenameView): queryset = InventoryItemTemplate.objects.all() +@register_model_view(InventoryItemTemplate, 'bulk_delete', path='delete', detail=False) class InventoryItemTemplateBulkDeleteView(generic.BulkDeleteView): queryset = InventoryItemTemplate.objects.all() table = tables.InventoryItemTemplateTable @@ -1770,6 +1871,7 @@ class InventoryItemTemplateBulkDeleteView(generic.BulkDeleteView): # Device roles # +@register_model_view(DeviceRole, 'list', path='', detail=False) class DeviceRoleListView(generic.ObjectListView): queryset = DeviceRole.objects.annotate( device_count=count_related(Device, 'role'), @@ -1790,6 +1892,7 @@ class DeviceRoleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(DeviceRole, 'add', detail=False) @register_model_view(DeviceRole, 'edit') class DeviceRoleEditView(generic.ObjectEditView): queryset = DeviceRole.objects.all() @@ -1801,11 +1904,13 @@ class DeviceRoleDeleteView(generic.ObjectDeleteView): queryset = DeviceRole.objects.all() +@register_model_view(DeviceRole, 'import', detail=False) class DeviceRoleBulkImportView(generic.BulkImportView): queryset = DeviceRole.objects.all() model_form = forms.DeviceRoleImportForm +@register_model_view(DeviceRole, 'bulk_edit', path='edit', detail=False) class DeviceRoleBulkEditView(generic.BulkEditView): queryset = DeviceRole.objects.annotate( device_count=count_related(Device, 'role'), @@ -1816,6 +1921,7 @@ class DeviceRoleBulkEditView(generic.BulkEditView): form = forms.DeviceRoleBulkEditForm +@register_model_view(DeviceRole, 'bulk_delete', path='delete', detail=False) class DeviceRoleBulkDeleteView(generic.BulkDeleteView): queryset = DeviceRole.objects.annotate( device_count=count_related(Device, 'role'), @@ -1829,6 +1935,7 @@ class DeviceRoleBulkDeleteView(generic.BulkDeleteView): # Platforms # +@register_model_view(Platform, 'list', path='', detail=False) class PlatformListView(generic.ObjectListView): queryset = Platform.objects.annotate( device_count=count_related(Device, 'platform'), @@ -1849,6 +1956,7 @@ class PlatformView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Platform, 'add', detail=False) @register_model_view(Platform, 'edit') class PlatformEditView(generic.ObjectEditView): queryset = Platform.objects.all() @@ -1860,11 +1968,13 @@ class PlatformDeleteView(generic.ObjectDeleteView): queryset = Platform.objects.all() +@register_model_view(Platform, 'import', detail=False) class PlatformBulkImportView(generic.BulkImportView): queryset = Platform.objects.all() model_form = forms.PlatformImportForm +@register_model_view(Platform, 'bulk_edit', path='edit', detail=False) class PlatformBulkEditView(generic.BulkEditView): queryset = Platform.objects.all() filterset = filtersets.PlatformFilterSet @@ -1872,6 +1982,7 @@ class PlatformBulkEditView(generic.BulkEditView): form = forms.PlatformBulkEditForm +@register_model_view(Platform, 'bulk_delete', path='delete', detail=False) class PlatformBulkDeleteView(generic.BulkDeleteView): queryset = Platform.objects.all() filterset = filtersets.PlatformFilterSet @@ -1882,6 +1993,7 @@ class PlatformBulkDeleteView(generic.BulkDeleteView): # Devices # +@register_model_view(Device, 'list', path='', detail=False) class DeviceListView(generic.ObjectListView): queryset = Device.objects.all() filterset = filtersets.DeviceFilterSet @@ -1909,6 +2021,7 @@ class DeviceView(generic.ObjectView): } +@register_model_view(Device, 'add', detail=False) @register_model_view(Device, 'edit') class DeviceEditView(generic.ObjectEditView): queryset = Device.objects.all() @@ -2176,6 +2289,7 @@ class DeviceVirtualMachinesView(generic.ObjectChildrenView): return self.child_model.objects.restrict(request.user, 'view').filter(cluster=parent.cluster, device=parent) +@register_model_view(Device, 'import', detail=False) class DeviceBulkImportView(generic.BulkImportView): queryset = Device.objects.all() model_form = forms.DeviceImportForm @@ -2192,6 +2306,7 @@ class DeviceBulkImportView(generic.BulkImportView): return obj +@register_model_view(Device, 'bulk_edit', path='edit', detail=False) class DeviceBulkEditView(generic.BulkEditView): queryset = Device.objects.prefetch_related('device_type__manufacturer') filterset = filtersets.DeviceFilterSet @@ -2199,12 +2314,14 @@ class DeviceBulkEditView(generic.BulkEditView): form = forms.DeviceBulkEditForm +@register_model_view(Device, 'bulk_delete', path='delete', detail=False) class DeviceBulkDeleteView(generic.BulkDeleteView): queryset = Device.objects.prefetch_related('device_type__manufacturer') filterset = filtersets.DeviceFilterSet table = tables.DeviceTable +@register_model_view(Device, 'bulk_rename', path='rename', detail=False) class DeviceBulkRenameView(generic.BulkRenameView): queryset = Device.objects.all() filterset = filtersets.DeviceFilterSet @@ -2220,6 +2337,7 @@ class DeviceContactsView(ObjectContactsView): # Modules # +@register_model_view(Module, 'list', path='', detail=False) class ModuleListView(generic.ObjectListView): queryset = Module.objects.prefetch_related('module_type__manufacturer') filterset = filtersets.ModuleFilterSet @@ -2237,6 +2355,7 @@ class ModuleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Module, 'add', detail=False) @register_model_view(Module, 'edit') class ModuleEditView(generic.ObjectEditView): queryset = Module.objects.all() @@ -2248,11 +2367,13 @@ class ModuleDeleteView(generic.ObjectDeleteView): queryset = Module.objects.all() +@register_model_view(Module, 'import', detail=False) class ModuleBulkImportView(generic.BulkImportView): queryset = Module.objects.all() model_form = forms.ModuleImportForm +@register_model_view(Module, 'bulk_edit', path='edit', detail=False) class ModuleBulkEditView(generic.BulkEditView): queryset = Module.objects.prefetch_related('module_type__manufacturer') filterset = filtersets.ModuleFilterSet @@ -2260,6 +2381,7 @@ class ModuleBulkEditView(generic.BulkEditView): form = forms.ModuleBulkEditForm +@register_model_view(Module, 'bulk_delete', path='delete', detail=False) class ModuleBulkDeleteView(generic.BulkDeleteView): queryset = Module.objects.prefetch_related('module_type__manufacturer') filterset = filtersets.ModuleFilterSet @@ -2270,6 +2392,7 @@ class ModuleBulkDeleteView(generic.BulkDeleteView): # Console ports # +@register_model_view(ConsolePort, 'list', path='', detail=False) class ConsolePortListView(generic.ObjectListView): queryset = ConsolePort.objects.all() filterset = filtersets.ConsolePortFilterSet @@ -2287,6 +2410,7 @@ class ConsolePortView(generic.ObjectView): queryset = ConsolePort.objects.all() +@register_model_view(ConsolePort, 'add', detail=False) class ConsolePortCreateView(generic.ComponentCreateView): queryset = ConsolePort.objects.all() form = forms.ConsolePortCreateForm @@ -2304,11 +2428,13 @@ class ConsolePortDeleteView(generic.ObjectDeleteView): queryset = ConsolePort.objects.all() +@register_model_view(ConsolePort, 'import', detail=False) class ConsolePortBulkImportView(generic.BulkImportView): queryset = ConsolePort.objects.all() model_form = forms.ConsolePortImportForm +@register_model_view(ConsolePort, 'bulk_edit', path='edit', detail=False) class ConsolePortBulkEditView(generic.BulkEditView): queryset = ConsolePort.objects.all() filterset = filtersets.ConsolePortFilterSet @@ -2316,14 +2442,17 @@ class ConsolePortBulkEditView(generic.BulkEditView): form = forms.ConsolePortBulkEditForm +@register_model_view(ConsolePort, 'bulk_rename', path='rename', detail=False) class ConsolePortBulkRenameView(generic.BulkRenameView): queryset = ConsolePort.objects.all() +@register_model_view(ConsolePort, 'bulk_disconnect', path='disconnect', detail=False) class ConsolePortBulkDisconnectView(BulkDisconnectView): queryset = ConsolePort.objects.all() +@register_model_view(ConsolePort, 'bulk_delete', path='delete', detail=False) class ConsolePortBulkDeleteView(generic.BulkDeleteView): queryset = ConsolePort.objects.all() filterset = filtersets.ConsolePortFilterSet @@ -2338,6 +2467,7 @@ register_model_view(ConsolePort, 'trace', kwargs={'model': ConsolePort})(PathTra # Console server ports # +@register_model_view(ConsoleServerPort, 'list', path='', detail=False) class ConsoleServerPortListView(generic.ObjectListView): queryset = ConsoleServerPort.objects.all() filterset = filtersets.ConsoleServerPortFilterSet @@ -2355,6 +2485,7 @@ class ConsoleServerPortView(generic.ObjectView): queryset = ConsoleServerPort.objects.all() +@register_model_view(ConsoleServerPort, 'add', detail=False) class ConsoleServerPortCreateView(generic.ComponentCreateView): queryset = ConsoleServerPort.objects.all() form = forms.ConsoleServerPortCreateForm @@ -2372,11 +2503,13 @@ class ConsoleServerPortDeleteView(generic.ObjectDeleteView): queryset = ConsoleServerPort.objects.all() +@register_model_view(ConsoleServerPort, 'import', detail=False) class ConsoleServerPortBulkImportView(generic.BulkImportView): queryset = ConsoleServerPort.objects.all() model_form = forms.ConsoleServerPortImportForm +@register_model_view(ConsoleServerPort, 'bulk_edit', path='edit', detail=False) class ConsoleServerPortBulkEditView(generic.BulkEditView): queryset = ConsoleServerPort.objects.all() filterset = filtersets.ConsoleServerPortFilterSet @@ -2384,14 +2517,17 @@ class ConsoleServerPortBulkEditView(generic.BulkEditView): form = forms.ConsoleServerPortBulkEditForm +@register_model_view(ConsoleServerPort, 'bulk_rename', path='rename', detail=False) class ConsoleServerPortBulkRenameView(generic.BulkRenameView): queryset = ConsoleServerPort.objects.all() +@register_model_view(ConsoleServerPort, 'bulk_disconnect', path='disconnect', detail=False) class ConsoleServerPortBulkDisconnectView(BulkDisconnectView): queryset = ConsoleServerPort.objects.all() +@register_model_view(ConsoleServerPort, 'bulk_delete', path='delete', detail=False) class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView): queryset = ConsoleServerPort.objects.all() filterset = filtersets.ConsoleServerPortFilterSet @@ -2406,6 +2542,7 @@ register_model_view(ConsoleServerPort, 'trace', kwargs={'model': ConsoleServerPo # Power ports # +@register_model_view(PowerPort, 'list', path='', detail=False) class PowerPortListView(generic.ObjectListView): queryset = PowerPort.objects.all() filterset = filtersets.PowerPortFilterSet @@ -2423,6 +2560,7 @@ class PowerPortView(generic.ObjectView): queryset = PowerPort.objects.all() +@register_model_view(PowerPort, 'add', detail=False) class PowerPortCreateView(generic.ComponentCreateView): queryset = PowerPort.objects.all() form = forms.PowerPortCreateForm @@ -2440,11 +2578,13 @@ class PowerPortDeleteView(generic.ObjectDeleteView): queryset = PowerPort.objects.all() +@register_model_view(PowerPort, 'import', detail=False) class PowerPortBulkImportView(generic.BulkImportView): queryset = PowerPort.objects.all() model_form = forms.PowerPortImportForm +@register_model_view(PowerPort, 'bulk_edit', path='edit', detail=False) class PowerPortBulkEditView(generic.BulkEditView): queryset = PowerPort.objects.all() filterset = filtersets.PowerPortFilterSet @@ -2452,14 +2592,17 @@ class PowerPortBulkEditView(generic.BulkEditView): form = forms.PowerPortBulkEditForm +@register_model_view(PowerPort, 'bulk_rename', path='rename', detail=False) class PowerPortBulkRenameView(generic.BulkRenameView): queryset = PowerPort.objects.all() +@register_model_view(PowerPort, 'bulk_disconnect', path='disconnect', detail=False) class PowerPortBulkDisconnectView(BulkDisconnectView): queryset = PowerPort.objects.all() +@register_model_view(PowerPort, 'bulk_delete', path='delete', detail=False) class PowerPortBulkDeleteView(generic.BulkDeleteView): queryset = PowerPort.objects.all() filterset = filtersets.PowerPortFilterSet @@ -2474,6 +2617,7 @@ register_model_view(PowerPort, 'trace', kwargs={'model': PowerPort})(PathTraceVi # Power outlets # +@register_model_view(PowerOutlet, 'list', path='', detail=False) class PowerOutletListView(generic.ObjectListView): queryset = PowerOutlet.objects.all() filterset = filtersets.PowerOutletFilterSet @@ -2491,6 +2635,7 @@ class PowerOutletView(generic.ObjectView): queryset = PowerOutlet.objects.all() +@register_model_view(PowerOutlet, 'add', detail=False) class PowerOutletCreateView(generic.ComponentCreateView): queryset = PowerOutlet.objects.all() form = forms.PowerOutletCreateForm @@ -2508,11 +2653,13 @@ class PowerOutletDeleteView(generic.ObjectDeleteView): queryset = PowerOutlet.objects.all() +@register_model_view(PowerOutlet, 'import', detail=False) class PowerOutletBulkImportView(generic.BulkImportView): queryset = PowerOutlet.objects.all() model_form = forms.PowerOutletImportForm +@register_model_view(PowerOutlet, 'bulk_edit', path='edit', detail=False) class PowerOutletBulkEditView(generic.BulkEditView): queryset = PowerOutlet.objects.all() filterset = filtersets.PowerOutletFilterSet @@ -2520,14 +2667,17 @@ class PowerOutletBulkEditView(generic.BulkEditView): form = forms.PowerOutletBulkEditForm +@register_model_view(PowerOutlet, 'bulk_rename', path='rename', detail=False) class PowerOutletBulkRenameView(generic.BulkRenameView): queryset = PowerOutlet.objects.all() +@register_model_view(PowerOutlet, 'bulk_disconnect', path='disconnect', detail=False) class PowerOutletBulkDisconnectView(BulkDisconnectView): queryset = PowerOutlet.objects.all() +@register_model_view(PowerOutlet, 'bulk_delete', path='delete', detail=False) class PowerOutletBulkDeleteView(generic.BulkDeleteView): queryset = PowerOutlet.objects.all() filterset = filtersets.PowerOutletFilterSet @@ -2542,6 +2692,7 @@ register_model_view(PowerOutlet, 'trace', kwargs={'model': PowerOutlet})(PathTra # Interfaces # +@register_model_view(Interface, 'list', path='', detail=False) class InterfaceListView(generic.ObjectListView): queryset = Interface.objects.all() filterset = filtersets.InterfaceFilterSet @@ -2571,7 +2722,7 @@ class InterfaceView(generic.ObjectView): # Get bridge interfaces bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance) - bridge_interfaces_tables = tables.InterfaceTable( + bridge_interfaces_table = tables.InterfaceTable( bridge_interfaces, exclude=('device', 'parent'), orderable=False @@ -2579,7 +2730,7 @@ class InterfaceView(generic.ObjectView): # Get child interfaces child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance) - child_interfaces_tables = tables.InterfaceTable( + child_interfaces_table = tables.InterfaceTable( child_interfaces, exclude=('device', 'parent'), orderable=False @@ -2609,13 +2760,14 @@ class InterfaceView(generic.ObjectView): return { 'vdc_table': vdc_table, - 'bridge_interfaces_table': bridge_interfaces_tables, - 'child_interfaces_table': child_interfaces_tables, + 'bridge_interfaces_table': bridge_interfaces_table, + 'child_interfaces_table': child_interfaces_table, 'vlan_table': vlan_table, 'vlan_translation_table': vlan_translation_table, } +@register_model_view(Interface, 'add', detail=False) class InterfaceCreateView(generic.ComponentCreateView): queryset = Interface.objects.all() form = forms.InterfaceCreateForm @@ -2633,26 +2785,41 @@ class InterfaceDeleteView(generic.ObjectDeleteView): queryset = Interface.objects.all() +@register_model_view(Interface, 'import', detail=False) class InterfaceBulkImportView(generic.BulkImportView): queryset = Interface.objects.all() model_form = forms.InterfaceImportForm +@register_model_view(Interface, 'bulk_edit', path='edit', detail=False) class InterfaceBulkEditView(generic.BulkEditView): queryset = Interface.objects.all() filterset = filtersets.InterfaceFilterSet table = tables.InterfaceTable form = forms.InterfaceBulkEditForm + def post_save_operations(self, form, obj): + super().post_save_operations(form, obj) + # Add/remove tagged VLANs + if obj.mode == InterfaceModeChoices.MODE_TAGGED: + if form.cleaned_data.get('add_tagged_vlans', None): + obj.tagged_vlans.add(*form.cleaned_data['add_tagged_vlans']) + if form.cleaned_data.get('remove_tagged_vlans', None): + obj.tagged_vlans.remove(*form.cleaned_data['remove_tagged_vlans']) + + +@register_model_view(Interface, 'bulk_rename', path='rename', detail=False) class InterfaceBulkRenameView(generic.BulkRenameView): queryset = Interface.objects.all() +@register_model_view(Interface, 'bulk_disconnect', path='disconnect', detail=False) class InterfaceBulkDisconnectView(BulkDisconnectView): queryset = Interface.objects.all() +@register_model_view(Interface, 'bulk_delete', path='delete', detail=False) class InterfaceBulkDeleteView(generic.BulkDeleteView): # Ensure child interfaces are deleted prior to their parents queryset = Interface.objects.order_by('device', 'parent', CollateAsChar('_name')) @@ -2668,6 +2835,7 @@ register_model_view(Interface, 'trace', kwargs={'model': Interface})(PathTraceVi # Front ports # +@register_model_view(FrontPort, 'list', path='', detail=False) class FrontPortListView(generic.ObjectListView): queryset = FrontPort.objects.all() filterset = filtersets.FrontPortFilterSet @@ -2685,6 +2853,7 @@ class FrontPortView(generic.ObjectView): queryset = FrontPort.objects.all() +@register_model_view(FrontPort, 'add', detail=False) class FrontPortCreateView(generic.ComponentCreateView): queryset = FrontPort.objects.all() form = forms.FrontPortCreateForm @@ -2702,11 +2871,13 @@ class FrontPortDeleteView(generic.ObjectDeleteView): queryset = FrontPort.objects.all() +@register_model_view(FrontPort, 'import', detail=False) class FrontPortBulkImportView(generic.BulkImportView): queryset = FrontPort.objects.all() model_form = forms.FrontPortImportForm +@register_model_view(FrontPort, 'bulk_edit', path='edit', detail=False) class FrontPortBulkEditView(generic.BulkEditView): queryset = FrontPort.objects.all() filterset = filtersets.FrontPortFilterSet @@ -2714,14 +2885,17 @@ class FrontPortBulkEditView(generic.BulkEditView): form = forms.FrontPortBulkEditForm +@register_model_view(FrontPort, 'bulk_rename', path='rename', detail=False) class FrontPortBulkRenameView(generic.BulkRenameView): queryset = FrontPort.objects.all() +@register_model_view(FrontPort, 'bulk_disconnect', path='disconnect', detail=False) class FrontPortBulkDisconnectView(BulkDisconnectView): queryset = FrontPort.objects.all() +@register_model_view(FrontPort, 'bulk_delete', path='delete', detail=False) class FrontPortBulkDeleteView(generic.BulkDeleteView): queryset = FrontPort.objects.all() filterset = filtersets.FrontPortFilterSet @@ -2736,6 +2910,7 @@ register_model_view(FrontPort, 'trace', kwargs={'model': FrontPort})(PathTraceVi # Rear ports # +@register_model_view(RearPort, 'list', path='', detail=False) class RearPortListView(generic.ObjectListView): queryset = RearPort.objects.all() filterset = filtersets.RearPortFilterSet @@ -2753,6 +2928,7 @@ class RearPortView(generic.ObjectView): queryset = RearPort.objects.all() +@register_model_view(RearPort, 'add', detail=False) class RearPortCreateView(generic.ComponentCreateView): queryset = RearPort.objects.all() form = forms.RearPortCreateForm @@ -2770,11 +2946,13 @@ class RearPortDeleteView(generic.ObjectDeleteView): queryset = RearPort.objects.all() +@register_model_view(RearPort, 'import', detail=False) class RearPortBulkImportView(generic.BulkImportView): queryset = RearPort.objects.all() model_form = forms.RearPortImportForm +@register_model_view(RearPort, 'bulk_edit', path='edit', detail=False) class RearPortBulkEditView(generic.BulkEditView): queryset = RearPort.objects.all() filterset = filtersets.RearPortFilterSet @@ -2782,14 +2960,17 @@ class RearPortBulkEditView(generic.BulkEditView): form = forms.RearPortBulkEditForm +@register_model_view(RearPort, 'bulk_rename', path='rename', detail=False) class RearPortBulkRenameView(generic.BulkRenameView): queryset = RearPort.objects.all() +@register_model_view(RearPort, 'bulk_disconnect', path='disconnect', detail=False) class RearPortBulkDisconnectView(BulkDisconnectView): queryset = RearPort.objects.all() +@register_model_view(RearPort, 'bulk_delete', path='delete', detail=False) class RearPortBulkDeleteView(generic.BulkDeleteView): queryset = RearPort.objects.all() filterset = filtersets.RearPortFilterSet @@ -2804,6 +2985,7 @@ register_model_view(RearPort, 'trace', kwargs={'model': RearPort})(PathTraceView # Module bays # +@register_model_view(ModuleBay, 'list', path='', detail=False) class ModuleBayListView(generic.ObjectListView): queryset = ModuleBay.objects.select_related('installed_module__module_type') filterset = filtersets.ModuleBayFilterSet @@ -2821,6 +3003,7 @@ class ModuleBayView(generic.ObjectView): queryset = ModuleBay.objects.all() +@register_model_view(ModuleBay, 'add', detail=False) class ModuleBayCreateView(generic.ComponentCreateView): queryset = ModuleBay.objects.all() form = forms.ModuleBayCreateForm @@ -2838,11 +3021,13 @@ class ModuleBayDeleteView(generic.ObjectDeleteView): queryset = ModuleBay.objects.all() +@register_model_view(ModuleBay, 'import', detail=False) class ModuleBayBulkImportView(generic.BulkImportView): queryset = ModuleBay.objects.all() model_form = forms.ModuleBayImportForm +@register_model_view(ModuleBay, 'bulk_edit', path='edit', detail=False) class ModuleBayBulkEditView(generic.BulkEditView): queryset = ModuleBay.objects.all() filterset = filtersets.ModuleBayFilterSet @@ -2850,10 +3035,12 @@ class ModuleBayBulkEditView(generic.BulkEditView): form = forms.ModuleBayBulkEditForm +@register_model_view(ModuleBay, 'bulk_rename', path='rename', detail=False) class ModuleBayBulkRenameView(generic.BulkRenameView): queryset = ModuleBay.objects.all() +@register_model_view(ModuleBay, 'bulk_delete', path='delete', detail=False) class ModuleBayBulkDeleteView(generic.BulkDeleteView): queryset = ModuleBay.objects.all() filterset = filtersets.ModuleBayFilterSet @@ -2864,6 +3051,7 @@ class ModuleBayBulkDeleteView(generic.BulkDeleteView): # Device bays # +@register_model_view(DeviceBay, 'list', path='', detail=False) class DeviceBayListView(generic.ObjectListView): queryset = DeviceBay.objects.all() filterset = filtersets.DeviceBayFilterSet @@ -2881,6 +3069,7 @@ class DeviceBayView(generic.ObjectView): queryset = DeviceBay.objects.all() +@register_model_view(DeviceBay, 'add', detail=False) class DeviceBayCreateView(generic.ComponentCreateView): queryset = DeviceBay.objects.all() form = forms.DeviceBayCreateForm @@ -2979,11 +3168,13 @@ class DeviceBayDepopulateView(generic.ObjectEditView): }) +@register_model_view(DeviceBay, 'import', detail=False) class DeviceBayBulkImportView(generic.BulkImportView): queryset = DeviceBay.objects.all() model_form = forms.DeviceBayImportForm +@register_model_view(DeviceBay, 'bulk_edit', path='edit', detail=False) class DeviceBayBulkEditView(generic.BulkEditView): queryset = DeviceBay.objects.all() filterset = filtersets.DeviceBayFilterSet @@ -2991,10 +3182,12 @@ class DeviceBayBulkEditView(generic.BulkEditView): form = forms.DeviceBayBulkEditForm +@register_model_view(DeviceBay, 'bulk_rename', path='rename', detail=False) class DeviceBayBulkRenameView(generic.BulkRenameView): queryset = DeviceBay.objects.all() +@register_model_view(DeviceBay, 'bulk_delete', path='delete', detail=False) class DeviceBayBulkDeleteView(generic.BulkDeleteView): queryset = DeviceBay.objects.all() filterset = filtersets.DeviceBayFilterSet @@ -3005,6 +3198,7 @@ class DeviceBayBulkDeleteView(generic.BulkDeleteView): # Inventory items # +@register_model_view(InventoryItem, 'list', path='', detail=False) class InventoryItemListView(generic.ObjectListView): queryset = InventoryItem.objects.all() filterset = filtersets.InventoryItemFilterSet @@ -3028,6 +3222,7 @@ class InventoryItemEditView(generic.ObjectEditView): form = forms.InventoryItemForm +@register_model_view(InventoryItem, 'add', detail=False) class InventoryItemCreateView(generic.ComponentCreateView): queryset = InventoryItem.objects.all() form = forms.InventoryItemCreateForm @@ -3039,11 +3234,13 @@ class InventoryItemDeleteView(generic.ObjectDeleteView): queryset = InventoryItem.objects.all() +@register_model_view(InventoryItem, 'import', detail=False) class InventoryItemBulkImportView(generic.BulkImportView): queryset = InventoryItem.objects.all() model_form = forms.InventoryItemImportForm +@register_model_view(InventoryItem, 'bulk_edit', path='edit', detail=False) class InventoryItemBulkEditView(generic.BulkEditView): queryset = InventoryItem.objects.all() filterset = filtersets.InventoryItemFilterSet @@ -3051,10 +3248,12 @@ class InventoryItemBulkEditView(generic.BulkEditView): form = forms.InventoryItemBulkEditForm +@register_model_view(InventoryItem, 'bulk_rename', path='rename', detail=False) class InventoryItemBulkRenameView(generic.BulkRenameView): queryset = InventoryItem.objects.all() +@register_model_view(InventoryItem, 'bulk_delete', path='delete', detail=False) class InventoryItemBulkDeleteView(generic.BulkDeleteView): queryset = InventoryItem.objects.all() filterset = filtersets.InventoryItemFilterSet @@ -3084,6 +3283,7 @@ class InventoryItemChildrenView(generic.ObjectChildrenView): # Inventory item roles # +@register_model_view(InventoryItemRole, 'list', path='', detail=False) class InventoryItemRoleListView(generic.ObjectListView): queryset = InventoryItemRole.objects.annotate( inventoryitem_count=count_related(InventoryItem, 'role'), @@ -3103,6 +3303,7 @@ class InventoryItemRoleView(generic.ObjectView): } +@register_model_view(InventoryItemRole, 'add', detail=False) @register_model_view(InventoryItemRole, 'edit') class InventoryItemRoleEditView(generic.ObjectEditView): queryset = InventoryItemRole.objects.all() @@ -3114,11 +3315,13 @@ class InventoryItemRoleDeleteView(generic.ObjectDeleteView): queryset = InventoryItemRole.objects.all() +@register_model_view(InventoryItemRole, 'import', detail=False) class InventoryItemRoleBulkImportView(generic.BulkImportView): queryset = InventoryItemRole.objects.all() model_form = forms.InventoryItemRoleImportForm +@register_model_view(InventoryItemRole, 'bulk_edit', path='edit', detail=False) class InventoryItemRoleBulkEditView(generic.BulkEditView): queryset = InventoryItemRole.objects.annotate( inventoryitem_count=count_related(InventoryItem, 'role'), @@ -3128,6 +3331,7 @@ class InventoryItemRoleBulkEditView(generic.BulkEditView): form = forms.InventoryItemRoleBulkEditForm +@register_model_view(InventoryItemRole, 'bulk_delete', path='delete', detail=False) class InventoryItemRoleBulkDeleteView(generic.BulkDeleteView): queryset = InventoryItemRole.objects.annotate( inventoryitem_count=count_related(InventoryItem, 'role'), @@ -3195,17 +3399,6 @@ class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView): default_return_url = 'dcim:device_list' -# class DeviceBulkAddFrontPortView(generic.BulkComponentCreateView): -# parent_model = Device -# parent_field = 'device' -# form = forms.FrontPortBulkCreateForm -# queryset = FrontPort.objects.all() -# model_form = forms.FrontPortForm -# filterset = filtersets.DeviceFilterSet -# table = tables.DeviceTable -# default_return_url = 'dcim:device_list' - - class DeviceBulkAddRearPortView(generic.BulkComponentCreateView): parent_model = Device parent_field = 'device' @@ -3254,6 +3447,7 @@ class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView): # Cables # +@register_model_view(Cable, 'list', path='', detail=False) class CableListView(generic.ObjectListView): queryset = Cable.objects.prefetch_related( 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location', @@ -3269,6 +3463,7 @@ class CableView(generic.ObjectView): queryset = Cable.objects.all() +@register_model_view(Cable, 'add', detail=False) @register_model_view(Cable, 'edit') class CableEditView(generic.ObjectEditView): queryset = Cable.objects.all() @@ -3316,11 +3511,13 @@ class CableDeleteView(generic.ObjectDeleteView): queryset = Cable.objects.all() +@register_model_view(Cable, 'import', detail=False) class CableBulkImportView(generic.BulkImportView): queryset = Cable.objects.all() model_form = forms.CableImportForm +@register_model_view(Cable, 'bulk_edit', path='edit', detail=False) class CableBulkEditView(generic.BulkEditView): queryset = Cable.objects.prefetch_related( 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location', @@ -3331,6 +3528,7 @@ class CableBulkEditView(generic.BulkEditView): form = forms.CableBulkEditForm +@register_model_view(Cable, 'bulk_delete', path='delete', detail=False) class CableBulkDeleteView(generic.BulkDeleteView): queryset = Cable.objects.prefetch_related( 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location', @@ -3396,6 +3594,7 @@ class InterfaceConnectionsListView(generic.ObjectListView): # Virtual chassis # +@register_model_view(VirtualChassis, 'list', path='', detail=False) class VirtualChassisListView(generic.ObjectListView): queryset = VirtualChassis.objects.all() table = tables.VirtualChassisTable @@ -3415,6 +3614,7 @@ class VirtualChassisView(generic.ObjectView): } +@register_model_view(VirtualChassis, 'add', detail=False) class VirtualChassisCreateView(generic.ObjectEditView): queryset = VirtualChassis.objects.all() form = forms.VirtualChassisCreateForm @@ -3535,7 +3735,9 @@ class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMix membership_form.save() messages.success(request, mark_safe( - _('Added member {device}').format(url=device.get_absolute_url(), device=escape(device)) + _('Added member {device}').format( + url=device.get_absolute_url(), device=escape(device) + ) )) if '_addanother' in request.POST: @@ -3610,11 +3812,13 @@ class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURL }) +@register_model_view(VirtualChassis, 'import', detail=False) class VirtualChassisBulkImportView(generic.BulkImportView): queryset = VirtualChassis.objects.all() model_form = forms.VirtualChassisImportForm +@register_model_view(VirtualChassis, 'bulk_edit', path='edit', detail=False) class VirtualChassisBulkEditView(generic.BulkEditView): queryset = VirtualChassis.objects.all() filterset = filtersets.VirtualChassisFilterSet @@ -3622,6 +3826,7 @@ class VirtualChassisBulkEditView(generic.BulkEditView): form = forms.VirtualChassisBulkEditForm +@register_model_view(VirtualChassis, 'bulk_delete', path='delete', detail=False) class VirtualChassisBulkDeleteView(generic.BulkDeleteView): queryset = VirtualChassis.objects.all() filterset = filtersets.VirtualChassisFilterSet @@ -3632,6 +3837,7 @@ class VirtualChassisBulkDeleteView(generic.BulkDeleteView): # Power panels # +@register_model_view(PowerPanel, 'list', path='', detail=False) class PowerPanelListView(generic.ObjectListView): queryset = PowerPanel.objects.annotate( powerfeed_count=count_related(PowerFeed, 'power_panel') @@ -3651,6 +3857,7 @@ class PowerPanelView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(PowerPanel, 'add', detail=False) @register_model_view(PowerPanel, 'edit') class PowerPanelEditView(generic.ObjectEditView): queryset = PowerPanel.objects.all() @@ -3662,11 +3869,13 @@ class PowerPanelDeleteView(generic.ObjectDeleteView): queryset = PowerPanel.objects.all() +@register_model_view(PowerPanel, 'import', detail=False) class PowerPanelBulkImportView(generic.BulkImportView): queryset = PowerPanel.objects.all() model_form = forms.PowerPanelImportForm +@register_model_view(PowerPanel, 'bulk_edit', path='edit', detail=False) class PowerPanelBulkEditView(generic.BulkEditView): queryset = PowerPanel.objects.all() filterset = filtersets.PowerPanelFilterSet @@ -3674,6 +3883,7 @@ class PowerPanelBulkEditView(generic.BulkEditView): form = forms.PowerPanelBulkEditForm +@register_model_view(PowerPanel, 'bulk_delete', path='delete', detail=False) class PowerPanelBulkDeleteView(generic.BulkDeleteView): queryset = PowerPanel.objects.annotate( powerfeed_count=count_related(PowerFeed, 'power_panel') @@ -3691,6 +3901,7 @@ class PowerPanelContactsView(ObjectContactsView): # Power feeds # +@register_model_view(PowerFeed, 'list', path='', detail=False) class PowerFeedListView(generic.ObjectListView): queryset = PowerFeed.objects.all() filterset = filtersets.PowerFeedFilterSet @@ -3703,6 +3914,7 @@ class PowerFeedView(generic.ObjectView): queryset = PowerFeed.objects.all() +@register_model_view(PowerFeed, 'add', detail=False) @register_model_view(PowerFeed, 'edit') class PowerFeedEditView(generic.ObjectEditView): queryset = PowerFeed.objects.all() @@ -3714,11 +3926,13 @@ class PowerFeedDeleteView(generic.ObjectDeleteView): queryset = PowerFeed.objects.all() +@register_model_view(PowerFeed, 'import', detail=False) class PowerFeedBulkImportView(generic.BulkImportView): queryset = PowerFeed.objects.all() model_form = forms.PowerFeedImportForm +@register_model_view(PowerFeed, 'bulk_edit', path='edit', detail=False) class PowerFeedBulkEditView(generic.BulkEditView): queryset = PowerFeed.objects.all() filterset = filtersets.PowerFeedFilterSet @@ -3726,10 +3940,12 @@ class PowerFeedBulkEditView(generic.BulkEditView): form = forms.PowerFeedBulkEditForm +@register_model_view(PowerFeed, 'bulk_disconnect', path='disconnect', detail=False) class PowerFeedBulkDisconnectView(BulkDisconnectView): queryset = PowerFeed.objects.all() +@register_model_view(PowerFeed, 'bulk_delete', path='delete', detail=False) class PowerFeedBulkDeleteView(generic.BulkDeleteView): queryset = PowerFeed.objects.all() filterset = filtersets.PowerFeedFilterSet @@ -3740,7 +3956,11 @@ class PowerFeedBulkDeleteView(generic.BulkDeleteView): register_model_view(PowerFeed, 'trace', kwargs={'model': PowerFeed})(PathTraceView) -# VDC +# +# Virtual device contexts +# + +@register_model_view(VirtualDeviceContext, 'list', path='', detail=False) class VirtualDeviceContextListView(generic.ObjectListView): queryset = VirtualDeviceContext.objects.annotate( interface_count=count_related(Interface, 'vdcs'), @@ -3766,6 +3986,7 @@ class VirtualDeviceContextView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(VirtualDeviceContext, 'add', detail=False) @register_model_view(VirtualDeviceContext, 'edit') class VirtualDeviceContextEditView(generic.ObjectEditView): queryset = VirtualDeviceContext.objects.all() @@ -3777,11 +3998,13 @@ class VirtualDeviceContextDeleteView(generic.ObjectDeleteView): queryset = VirtualDeviceContext.objects.all() +@register_model_view(VirtualDeviceContext, 'import', detail=False) class VirtualDeviceContextBulkImportView(generic.BulkImportView): queryset = VirtualDeviceContext.objects.all() model_form = forms.VirtualDeviceContextImportForm +@register_model_view(VirtualDeviceContext, 'bulk_edit', path='edit', detail=False) class VirtualDeviceContextBulkEditView(generic.BulkEditView): queryset = VirtualDeviceContext.objects.all() filterset = filtersets.VirtualDeviceContextFilterSet @@ -3789,7 +4012,58 @@ class VirtualDeviceContextBulkEditView(generic.BulkEditView): form = forms.VirtualDeviceContextBulkEditForm +@register_model_view(VirtualDeviceContext, 'bulk_delete', path='delete', detail=False) class VirtualDeviceContextBulkDeleteView(generic.BulkDeleteView): queryset = VirtualDeviceContext.objects.all() filterset = filtersets.VirtualDeviceContextFilterSet table = tables.VirtualDeviceContextTable + + +# +# MAC addresses +# + +@register_model_view(MACAddress, 'list', path='', detail=False) +class MACAddressListView(generic.ObjectListView): + queryset = MACAddress.objects.all() + filterset = filtersets.MACAddressFilterSet + filterset_form = forms.MACAddressFilterForm + table = tables.MACAddressTable + + +@register_model_view(MACAddress) +class MACAddressView(generic.ObjectView): + queryset = MACAddress.objects.all() + + +@register_model_view(MACAddress, 'add', detail=False) +@register_model_view(MACAddress, 'edit') +class MACAddressEditView(generic.ObjectEditView): + queryset = MACAddress.objects.all() + form = forms.MACAddressForm + + +@register_model_view(MACAddress, 'delete') +class MACAddressDeleteView(generic.ObjectDeleteView): + queryset = MACAddress.objects.all() + + +@register_model_view(MACAddress, 'import', detail=False) +class MACAddressBulkImportView(generic.BulkImportView): + queryset = MACAddress.objects.all() + model_form = forms.MACAddressImportForm + + +@register_model_view(MACAddress, 'bulk_edit', path='edit', detail=False) +class MACAddressBulkEditView(generic.BulkEditView): + queryset = MACAddress.objects.all() + filterset = filtersets.MACAddressFilterSet + table = tables.MACAddressTable + form = forms.MACAddressBulkEditForm + + +@register_model_view(MACAddress, 'bulk_delete', path='delete', detail=False) +class MACAddressBulkDeleteView(generic.BulkDeleteView): + queryset = MACAddress.objects.all() + filterset = filtersets.MACAddressFilterSet + table = tables.MACAddressTable diff --git a/netbox/extras/jobs.py b/netbox/extras/jobs.py index a913fe456..190166b5b 100644 --- a/netbox/extras/jobs.py +++ b/netbox/extras/jobs.py @@ -22,9 +22,7 @@ class ScriptJob(JobRunner): """ class Meta: - # An explicit job name is not set because it doesn't make sense in this context. Currently, there's no scenario - # where jobs other than this one are used. Therefore, it is hidden, resulting in a cleaner job table overview. - name = '' + name = 'Run Script' def run_script(self, script, request, data, commit): """ diff --git a/netbox/extras/management/commands/reindex.py b/netbox/extras/management/commands/reindex.py index 21442be93..5495bbf5f 100644 --- a/netbox/extras/management/commands/reindex.py +++ b/netbox/extras/management/commands/reindex.py @@ -53,7 +53,8 @@ class Command(BaseCommand): else: raise CommandError( - f"Invalid model: {label}. Model names must be in the format or .." + f"Invalid model: {label}. Model names must be in the format or " + f".." ) return indexers diff --git a/netbox/extras/migrations/0001_squashed.py b/netbox/extras/migrations/0001_squashed.py index 6f1f77e53..a2514fa5e 100644 --- a/netbox/extras/migrations/0001_squashed.py +++ b/netbox/extras/migrations/0001_squashed.py @@ -9,7 +9,6 @@ import utilities.validators class Migration(migrations.Migration): - initial = True dependencies = [ @@ -99,8 +98,22 @@ class Migration(migrations.Migration): fields=[ ('object_id', models.IntegerField(db_index=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_tagged_items', to='contenttypes.contenttype')), - ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_items', to='extras.tag')), + ( + 'content_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='%(app_label)s_%(class)s_tagged_items', + to='contenttypes.contenttype', + ), + ), + ( + 'tag', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='%(app_label)s_%(class)s_items', + to='extras.tag', + ), + ), ], ), migrations.CreateModel( @@ -116,9 +129,32 @@ class Migration(migrations.Migration): ('object_repr', models.CharField(editable=False, max_length=200)), ('prechange_data', models.JSONField(blank=True, editable=False, null=True)), ('postchange_data', models.JSONField(blank=True, editable=False, null=True)), - ('changed_object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('related_object_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='changes', to=settings.AUTH_USER_MODEL)), + ( + 'changed_object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype' + ), + ), + ( + 'related_object_type', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + 'user', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='changes', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'ordering': ['-time'], @@ -133,8 +169,16 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(auto_now_add=True)), ('kind', models.CharField(default='info', max_length=30)), ('comments', models.TextField()), - ('assigned_object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ( + 'assigned_object_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + ( + 'created_by', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + ), + ), ], options={ 'verbose_name_plural': 'journal entries', @@ -151,8 +195,24 @@ class Migration(migrations.Migration): ('status', models.CharField(default='pending', max_length=30)), ('data', models.JSONField(blank=True, null=True)), ('job_id', models.UUIDField(unique=True)), - ('obj_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='job_results', to='contenttypes.contenttype')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ( + 'obj_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='job_results', + to='contenttypes.contenttype', + ), + ), + ( + 'user', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'ordering': ['obj_type', 'name', '-created'], @@ -163,12 +223,20 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(primary_key=True, serialize=False)), ('object_id', models.PositiveIntegerField()), - ('image', models.ImageField(height_field='image_height', upload_to=extras.utils.image_upload, width_field='image_width')), + ( + 'image', + models.ImageField( + height_field='image_height', upload_to=extras.utils.image_upload, width_field='image_width' + ), + ), ('image_height', models.PositiveSmallIntegerField()), ('image_width', models.PositiveSmallIntegerField()), ('name', models.CharField(blank=True, max_length=50)), ('created', models.DateTimeField(auto_now_add=True)), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ( + 'content_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), ], options={ 'ordering': ('name', 'pk'), @@ -184,7 +252,10 @@ class Migration(migrations.Migration): ('mime_type', models.CharField(blank=True, max_length=50)), ('file_extension', models.CharField(blank=True, max_length=15)), ('as_attachment', models.BooleanField(default=True)), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ( + 'content_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), ], options={ 'ordering': ['content_type', 'name'], @@ -201,7 +272,10 @@ class Migration(migrations.Migration): ('group_name', models.CharField(blank=True, max_length=50)), ('button_class', models.CharField(default='default', max_length=30)), ('new_window', models.BooleanField(default=False)), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ( + 'content_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), ], options={ 'ordering': ['group_name', 'weight', 'name'], @@ -221,8 +295,16 @@ class Migration(migrations.Migration): ('weight', models.PositiveSmallIntegerField(default=100)), ('validation_minimum', models.PositiveIntegerField(blank=True, null=True)), ('validation_maximum', models.PositiveIntegerField(blank=True, null=True)), - ('validation_regex', models.CharField(blank=True, max_length=500, validators=[utilities.validators.validate_regex])), - ('choices', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, null=True, size=None)), + ( + 'validation_regex', + models.CharField(blank=True, max_length=500, validators=[utilities.validators.validate_regex]), + ), + ( + 'choices', + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=100), blank=True, null=True, size=None + ), + ), ('content_types', models.ManyToManyField(related_name='custom_fields', to='contenttypes.ContentType')), ], options={ diff --git a/netbox/extras/migrations/0002_squashed_0059.py b/netbox/extras/migrations/0002_squashed_0059.py index a403a0e19..b664b286e 100644 --- a/netbox/extras/migrations/0002_squashed_0059.py +++ b/netbox/extras/migrations/0002_squashed_0059.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('dcim', '0002_auto_20160622_1821'), ('extras', '0001_initial'), diff --git a/netbox/extras/migrations/0060_squashed_0086.py b/netbox/extras/migrations/0060_squashed_0086.py index 0d5d03008..3bde7480f 100644 --- a/netbox/extras/migrations/0060_squashed_0086.py +++ b/netbox/extras/migrations/0060_squashed_0086.py @@ -12,7 +12,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('extras', '0060_customlink_button_class'), ('extras', '0061_extras_change_logging'), @@ -40,7 +39,7 @@ class Migration(migrations.Migration): ('extras', '0083_search'), ('extras', '0084_staging'), ('extras', '0085_synced_data'), - ('extras', '0086_configtemplate') + ('extras', '0086_configtemplate'), ] dependencies = [ @@ -114,7 +113,23 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='customfield', name='name', - field=models.CharField(max_length=50, unique=True, validators=[django.core.validators.RegexValidator(flags=re.RegexFlag['IGNORECASE'], message='Only alphanumeric characters and underscores are allowed.', regex='^[a-z0-9_]+$'), django.core.validators.RegexValidator(flags=re.RegexFlag['IGNORECASE'], inverse_match=True, message='Double underscores are not permitted in custom field names.', regex='__')]), + field=models.CharField( + max_length=50, + unique=True, + validators=[ + django.core.validators.RegexValidator( + flags=re.RegexFlag['IGNORECASE'], + message='Only alphanumeric characters and underscores are allowed.', + regex='^[a-z0-9_]+$', + ), + django.core.validators.RegexValidator( + flags=re.RegexFlag['IGNORECASE'], + inverse_match=True, + message='Double underscores are not permitted in custom field names.', + regex='__', + ), + ], + ), ), migrations.AlterField( model_name='customfield', @@ -134,7 +149,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='customfield', name='object_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype' + ), ), migrations.AddField( model_name='customlink', @@ -314,11 +331,16 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='exporttemplate', - constraint=models.UniqueConstraint(fields=('content_type', 'name'), name='extras_exporttemplate_unique_content_type_name'), + constraint=models.UniqueConstraint( + fields=('content_type', 'name'), name='extras_exporttemplate_unique_content_type_name' + ), ), migrations.AddConstraint( model_name='webhook', - constraint=models.UniqueConstraint(fields=('payload_url', 'type_create', 'type_update', 'type_delete'), name='extras_webhook_unique_payload_url_types'), + constraint=models.UniqueConstraint( + fields=('payload_url', 'type_create', 'type_update', 'type_delete'), + name='extras_webhook_unique_payload_url_types', + ), ), migrations.AddField( model_name='jobresult', @@ -328,7 +350,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='jobresult', name='interval', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]), + field=models.PositiveIntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)] + ), ), migrations.AddField( model_name='jobresult', @@ -379,7 +403,12 @@ class Migration(migrations.Migration): ('shared', models.BooleanField(default=True)), ('parameters', models.JSONField()), ('content_types', models.ManyToManyField(related_name='saved_filters', to='contenttypes.contenttype')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + ), + ), ], options={ 'ordering': ('weight', 'name'), @@ -400,7 +429,12 @@ class Migration(migrations.Migration): ('type', models.CharField(max_length=30)), ('value', extras.fields.CachedValueField()), ('weight', models.PositiveSmallIntegerField(default=1000)), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype')), + ( + 'object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype' + ), + ), ], options={ 'ordering': ('weight', 'object_type', 'object_id'), @@ -414,7 +448,12 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('name', models.CharField(max_length=100, unique=True)), ('description', models.CharField(blank=True, max_length=200)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + ), + ), ], options={ 'ordering': ('name',), @@ -429,8 +468,18 @@ class Migration(migrations.Migration): ('action', models.CharField(max_length=20)), ('object_id', models.PositiveBigIntegerField(blank=True, null=True)), ('data', models.JSONField(blank=True, null=True)), - ('branch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='staged_changes', to='extras.branch')), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype')), + ( + 'branch', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='staged_changes', to='extras.branch' + ), + ), + ( + 'object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype' + ), + ), ], options={ 'ordering': ('pk',), @@ -439,7 +488,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='configcontext', name='data_file', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='core.datafile', + ), ), migrations.AddField( model_name='configcontext', @@ -449,7 +504,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='configcontext', name='data_source', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='core.datasource', + ), ), migrations.AddField( model_name='configcontext', @@ -464,7 +525,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='exporttemplate', name='data_file', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='core.datafile', + ), ), migrations.AddField( model_name='exporttemplate', @@ -474,7 +541,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='exporttemplate', name='data_source', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='core.datasource', + ), ), migrations.AddField( model_name='exporttemplate', @@ -498,8 +571,26 @@ class Migration(migrations.Migration): ('description', models.CharField(blank=True, max_length=200)), ('template_code', models.TextField()), ('environment_params', models.JSONField(blank=True, default=dict, null=True)), - ('data_file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile')), - ('data_source', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource')), + ( + 'data_file', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='core.datafile', + ), + ), + ( + 'data_source', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='core.datasource', + ), + ), ('auto_sync_enabled', models.BooleanField(default=False)), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], diff --git a/netbox/extras/migrations/0087_squashed_0098.py b/netbox/extras/migrations/0087_squashed_0098.py index bbe7f79f5..839f4cbe4 100644 --- a/netbox/extras/migrations/0087_squashed_0098.py +++ b/netbox/extras/migrations/0087_squashed_0098.py @@ -9,7 +9,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('extras', '0087_dashboard'), ('extras', '0088_jobresult_webhooks'), @@ -22,7 +21,7 @@ class Migration(migrations.Migration): ('extras', '0095_bookmarks'), ('extras', '0096_customfieldchoiceset'), ('extras', '0097_customfield_remove_choices'), - ('extras', '0098_webhook_custom_field_data_webhook_tags') + ('extras', '0098_webhook_custom_field_data_webhook_tags'), ] dependencies = [ @@ -39,7 +38,14 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('layout', models.JSONField(default=list)), ('config', models.JSONField(default=dict)), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dashboard', to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name='dashboard', + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddField( @@ -64,8 +70,7 @@ class Migration(migrations.Migration): ), migrations.CreateModel( name='ReportModule', - fields=[ - ], + fields=[], options={ 'proxy': True, 'ordering': ('file_root', 'file_path'), @@ -76,8 +81,7 @@ class Migration(migrations.Migration): ), migrations.CreateModel( name='ScriptModule', - fields=[ - ], + fields=[], options={ 'proxy': True, 'ordering': ('file_root', 'file_path'), @@ -108,7 +112,10 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True)), ('object_id', models.PositiveBigIntegerField()), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ( + 'object_type', + models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], options={ @@ -117,7 +124,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='bookmark', - constraint=models.UniqueConstraint(fields=('object_type', 'object_id', 'user'), name='extras_bookmark_unique_per_object_and_user'), + constraint=models.UniqueConstraint( + fields=('object_type', 'object_id', 'user'), name='extras_bookmark_unique_per_object_and_user' + ), ), migrations.CreateModel( name='CustomFieldChoiceSet', @@ -128,7 +137,17 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=100, unique=True)), ('description', models.CharField(blank=True, max_length=200)), ('base_choices', models.CharField(blank=True, max_length=50)), - ('extra_choices', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), size=2), blank=True, null=True, size=None)), + ( + 'extra_choices', + django.contrib.postgres.fields.ArrayField( + base_field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=100), size=2 + ), + blank=True, + null=True, + size=None, + ), + ), ('order_alphabetically', models.BooleanField(default=False)), ], options={ @@ -138,7 +157,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='customfield', name='choice_set', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='choices_for', to='extras.customfieldchoiceset'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='choices_for', + to='extras.customfieldchoiceset', + ), ), migrations.RemoveField( model_name='customfield', diff --git a/netbox/extras/migrations/0099_cachedvalue_ordering.py b/netbox/extras/migrations/0099_cachedvalue_ordering.py index 242ffd983..36b91d59b 100644 --- a/netbox/extras/migrations/0099_cachedvalue_ordering.py +++ b/netbox/extras/migrations/0099_cachedvalue_ordering.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('extras', '0098_webhook_custom_field_data_webhook_tags'), ] diff --git a/netbox/extras/migrations/0100_customfield_ui_attrs.py b/netbox/extras/migrations/0100_customfield_ui_attrs.py index a4a713a86..b1a404d16 100644 --- a/netbox/extras/migrations/0100_customfield_ui_attrs.py +++ b/netbox/extras/migrations/0100_customfield_ui_attrs.py @@ -14,7 +14,6 @@ def update_ui_attrs(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0099_cachedvalue_ordering'), ] @@ -30,10 +29,7 @@ class Migration(migrations.Migration): name='ui_visible', field=models.CharField(default='always', max_length=50), ), - migrations.RunPython( - code=update_ui_attrs, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_ui_attrs, reverse_code=migrations.RunPython.noop), migrations.RemoveField( model_name='customfield', name='ui_visibility', diff --git a/netbox/extras/migrations/0101_eventrule.py b/netbox/extras/migrations/0101_eventrule.py index 3d236c847..605307c27 100644 --- a/netbox/extras/migrations/0101_eventrule.py +++ b/netbox/extras/migrations/0101_eventrule.py @@ -8,8 +8,8 @@ from extras.choices import * def move_webhooks(apps, schema_editor): - Webhook = apps.get_model("extras", "Webhook") - EventRule = apps.get_model("extras", "EventRule") + Webhook = apps.get_model('extras', 'Webhook') + EventRule = apps.get_model('extras', 'EventRule') webhook_ct = ContentType.objects.get_for_model(Webhook).pk for webhook in Webhook.objects.all(): @@ -39,7 +39,6 @@ class Migration(migrations.Migration): ] operations = [ - # Create the EventRule model migrations.CreateModel( name='EventRule', @@ -93,12 +92,12 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='eventrule', - index=models.Index(fields=['action_object_type', 'action_object_id'], name='extras_even_action__d9e2af_idx'), + index=models.Index( + fields=['action_object_type', 'action_object_id'], name='extras_even_action__d9e2af_idx' + ), ), - # Replicate Webhook data migrations.RunPython(move_webhooks), - # Remove obsolete fields from Webhook migrations.RemoveConstraint( model_name='webhook', @@ -136,7 +135,6 @@ class Migration(migrations.Migration): model_name='webhook', name='type_update', ), - # Add description field to Webhook migrations.AddField( model_name='webhook', diff --git a/netbox/extras/migrations/0102_move_configrevision.py b/netbox/extras/migrations/0102_move_configrevision.py index 36eef1205..64ff8c9ad 100644 --- a/netbox/extras/migrations/0102_move_configrevision.py +++ b/netbox/extras/migrations/0102_move_configrevision.py @@ -13,7 +13,6 @@ def update_content_type(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0101_eventrule'), ] @@ -32,8 +31,5 @@ class Migration(migrations.Migration): ), ], ), - migrations.RunPython( - code=update_content_type, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_content_type, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/migrations/0103_gfk_indexes.py b/netbox/extras/migrations/0103_gfk_indexes.py index 2ccbdb2ff..f32b2e116 100644 --- a/netbox/extras/migrations/0103_gfk_indexes.py +++ b/netbox/extras/migrations/0103_gfk_indexes.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0102_move_configrevision'), ] @@ -20,15 +19,21 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='journalentry', - index=models.Index(fields=['assigned_object_type', 'assigned_object_id'], name='extras_jour_assigne_76510f_idx'), + index=models.Index( + fields=['assigned_object_type', 'assigned_object_id'], name='extras_jour_assigne_76510f_idx' + ), ), migrations.AddIndex( model_name='objectchange', - index=models.Index(fields=['changed_object_type', 'changed_object_id'], name='extras_obje_changed_927fe5_idx'), + index=models.Index( + fields=['changed_object_type', 'changed_object_id'], name='extras_obje_changed_927fe5_idx' + ), ), migrations.AddIndex( model_name='objectchange', - index=models.Index(fields=['related_object_type', 'related_object_id'], name='extras_obje_related_bfcdef_idx'), + index=models.Index( + fields=['related_object_type', 'related_object_id'], name='extras_obje_related_bfcdef_idx' + ), ), migrations.AddIndex( model_name='stagedchange', diff --git a/netbox/extras/migrations/0105_customfield_min_max_values.py b/netbox/extras/migrations/0105_customfield_min_max_values.py index bcf3f97bd..71a0dcc68 100644 --- a/netbox/extras/migrations/0105_customfield_min_max_values.py +++ b/netbox/extras/migrations/0105_customfield_min_max_values.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0104_stagedchange_remove_change_logging'), ] diff --git a/netbox/extras/migrations/0106_bookmark_user_cascade_deletion.py b/netbox/extras/migrations/0106_bookmark_user_cascade_deletion.py index d7bef2f0b..bc0e1bbd0 100644 --- a/netbox/extras/migrations/0106_bookmark_user_cascade_deletion.py +++ b/netbox/extras/migrations/0106_bookmark_user_cascade_deletion.py @@ -6,7 +6,6 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('extras', '0105_customfield_min_max_values'), diff --git a/netbox/extras/migrations/0107_cachedvalue_extras_cachedvalue_object.py b/netbox/extras/migrations/0107_cachedvalue_extras_cachedvalue_object.py index 15ce375a2..3f2907192 100644 --- a/netbox/extras/migrations/0107_cachedvalue_extras_cachedvalue_object.py +++ b/netbox/extras/migrations/0107_cachedvalue_extras_cachedvalue_object.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0106_bookmark_user_cascade_deletion'), ] diff --git a/netbox/extras/migrations/0108_convert_reports_to_scripts.py b/netbox/extras/migrations/0108_convert_reports_to_scripts.py index b547c41c3..948bac754 100644 --- a/netbox/extras/migrations/0108_convert_reports_to_scripts.py +++ b/netbox/extras/migrations/0108_convert_reports_to_scripts.py @@ -12,16 +12,12 @@ def convert_reportmodule_jobs(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0107_cachedvalue_extras_cachedvalue_object'), ] operations = [ - migrations.RunPython( - code=convert_reportmodule_jobs, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=convert_reportmodule_jobs, reverse_code=migrations.RunPython.noop), migrations.DeleteModel( name='Report', ), diff --git a/netbox/extras/migrations/0109_script_model.py b/netbox/extras/migrations/0109_script_model.py index 2fa0bf8aa..706a776af 100644 --- a/netbox/extras/migrations/0109_script_model.py +++ b/netbox/extras/migrations/0109_script_model.py @@ -55,9 +55,10 @@ def get_module_scripts(scriptmodule): """ Return a dictionary mapping of name and script class inside the passed ScriptModule. """ + def get_name(cls): # For child objects in submodules use the full import path w/o the root module as the name - return cls.full_name.split(".", maxsplit=1)[1] + return cls.full_name.split('.', maxsplit=1)[1] loader = SourceFileLoader(get_python_name(scriptmodule), get_full_path(scriptmodule)) try: @@ -100,17 +101,13 @@ def update_scripts(apps, schema_editor): ) # Update all Jobs associated with this ScriptModule & script name to point to the new Script object - Job.objects.filter( - object_type_id=scriptmodule_ct.id, - object_id=module.pk, - name=script_name - ).update(object_type_id=script_ct.id, object_id=script.pk) + Job.objects.filter(object_type_id=scriptmodule_ct.id, object_id=module.pk, name=script_name).update( + object_type_id=script_ct.id, object_id=script.pk + ) # Update all Jobs associated with this ScriptModule & script name to point to the new Script object - Job.objects.filter( - object_type_id=reportmodule_ct.id, - object_id=module.pk, - name=script_name - ).update(object_type_id=script_ct.id, object_id=script.pk) + Job.objects.filter(object_type_id=reportmodule_ct.id, object_id=module.pk, name=script_name).update( + object_type_id=script_ct.id, object_id=script.pk + ) def update_event_rules(apps, schema_editor): @@ -129,15 +126,12 @@ def update_event_rules(apps, schema_editor): for eventrule in EventRule.objects.filter(action_object_type=scriptmodule_ct): name = eventrule.action_parameters.get('script_name') obj, __ = Script.objects.get_or_create( - module_id=eventrule.action_object_id, - name=name, - defaults={'is_executable': False} + module_id=eventrule.action_object_id, name=name, defaults={'is_executable': False} ) EventRule.objects.filter(pk=eventrule.pk).update(action_object_type=script_ct, action_object_id=obj.id) class Migration(migrations.Migration): - dependencies = [ ('extras', '0108_convert_reports_to_scripts'), ] @@ -148,8 +142,16 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(editable=False, max_length=79)), - ('module', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='scripts', to='extras.scriptmodule')), - ('is_executable', models.BooleanField(editable=False, default=True)) + ( + 'module', + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name='scripts', + to='extras.scriptmodule', + ), + ), + ('is_executable', models.BooleanField(editable=False, default=True)), ], options={ 'ordering': ('module', 'name'), @@ -159,12 +161,6 @@ class Migration(migrations.Migration): model_name='script', constraint=models.UniqueConstraint(fields=('name', 'module'), name='extras_script_unique_name_module'), ), - migrations.RunPython( - code=update_scripts, - reverse_code=migrations.RunPython.noop - ), - migrations.RunPython( - code=update_event_rules, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_scripts, reverse_code=migrations.RunPython.noop), + migrations.RunPython(code=update_event_rules, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/migrations/0110_remove_eventrule_action_parameters.py b/netbox/extras/migrations/0110_remove_eventrule_action_parameters.py index b7373bdce..494107643 100644 --- a/netbox/extras/migrations/0110_remove_eventrule_action_parameters.py +++ b/netbox/extras/migrations/0110_remove_eventrule_action_parameters.py @@ -2,7 +2,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('extras', '0109_script_model'), ] diff --git a/netbox/extras/migrations/0111_rename_content_types.py b/netbox/extras/migrations/0111_rename_content_types.py index acd6aef0f..a9f80b146 100644 --- a/netbox/extras/migrations/0111_rename_content_types.py +++ b/netbox/extras/migrations/0111_rename_content_types.py @@ -3,7 +3,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0010_gfk_indexes'), ('extras', '0110_remove_eventrule_action_parameters'), @@ -24,16 +23,19 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='customfield', name='object_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.objecttype'), - ), - migrations.RunSQL( - "ALTER TABLE IF EXISTS extras_customfield_content_types_id_seq RENAME TO extras_customfield_object_types_id_seq" + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.objecttype' + ), ), + migrations.RunSQL(( + 'ALTER TABLE IF EXISTS extras_customfield_content_types_id_seq ' + 'RENAME TO extras_customfield_object_types_id_seq' + )), # Pre-v2.10 sequence name (see #15605) - migrations.RunSQL( - "ALTER TABLE IF EXISTS extras_customfield_obj_type_id_seq RENAME TO extras_customfield_object_types_id_seq" - ), - + migrations.RunSQL(( + 'ALTER TABLE IF EXISTS extras_customfield_obj_type_id_seq ' + 'RENAME TO extras_customfield_object_types_id_seq' + )), # Custom links migrations.RenameField( model_name='customlink', @@ -46,9 +48,8 @@ class Migration(migrations.Migration): field=models.ManyToManyField(related_name='custom_links', to='core.objecttype'), ), migrations.RunSQL( - "ALTER TABLE extras_customlink_content_types_id_seq RENAME TO extras_customlink_object_types_id_seq" + 'ALTER TABLE extras_customlink_content_types_id_seq RENAME TO extras_customlink_object_types_id_seq' ), - # Event rules migrations.RenameField( model_name='eventrule', @@ -61,9 +62,8 @@ class Migration(migrations.Migration): field=models.ManyToManyField(related_name='event_rules', to='core.objecttype'), ), migrations.RunSQL( - "ALTER TABLE extras_eventrule_content_types_id_seq RENAME TO extras_eventrule_object_types_id_seq" + 'ALTER TABLE extras_eventrule_content_types_id_seq RENAME TO extras_eventrule_object_types_id_seq' ), - # Export templates migrations.RenameField( model_name='exporttemplate', @@ -76,9 +76,8 @@ class Migration(migrations.Migration): field=models.ManyToManyField(related_name='export_templates', to='core.objecttype'), ), migrations.RunSQL( - "ALTER TABLE extras_exporttemplate_content_types_id_seq RENAME TO extras_exporttemplate_object_types_id_seq" + 'ALTER TABLE extras_exporttemplate_content_types_id_seq RENAME TO extras_exporttemplate_object_types_id_seq' ), - # Saved filters migrations.RenameField( model_name='savedfilter', @@ -91,9 +90,8 @@ class Migration(migrations.Migration): field=models.ManyToManyField(related_name='saved_filters', to='core.objecttype'), ), migrations.RunSQL( - "ALTER TABLE extras_savedfilter_content_types_id_seq RENAME TO extras_savedfilter_object_types_id_seq" + 'ALTER TABLE extras_savedfilter_content_types_id_seq RENAME TO extras_savedfilter_object_types_id_seq' ), - # Image attachments migrations.RemoveIndex( model_name='imageattachment', diff --git a/netbox/extras/migrations/0112_tag_update_object_types.py b/netbox/extras/migrations/0112_tag_update_object_types.py index 87ec117a4..e863ba8c3 100644 --- a/netbox/extras/migrations/0112_tag_update_object_types.py +++ b/netbox/extras/migrations/0112_tag_update_object_types.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0010_gfk_indexes'), ('extras', '0111_rename_content_types'), diff --git a/netbox/extras/migrations/0113_customfield_rename_object_type.py b/netbox/extras/migrations/0113_customfield_rename_object_type.py index 73c4a2a61..9ad9fbbc4 100644 --- a/netbox/extras/migrations/0113_customfield_rename_object_type.py +++ b/netbox/extras/migrations/0113_customfield_rename_object_type.py @@ -2,7 +2,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('extras', '0112_tag_update_object_types'), ] diff --git a/netbox/extras/migrations/0114_customfield_add_comments.py b/netbox/extras/migrations/0114_customfield_add_comments.py index cd85db1ba..ad9e3d46f 100644 --- a/netbox/extras/migrations/0114_customfield_add_comments.py +++ b/netbox/extras/migrations/0114_customfield_add_comments.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0113_customfield_rename_object_type'), ] diff --git a/netbox/extras/migrations/0115_convert_dashboard_widgets.py b/netbox/extras/migrations/0115_convert_dashboard_widgets.py index c85c83ecf..28f6eade9 100644 --- a/netbox/extras/migrations/0115_convert_dashboard_widgets.py +++ b/netbox/extras/migrations/0115_convert_dashboard_widgets.py @@ -16,14 +16,10 @@ def update_dashboard_widgets(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0114_customfield_add_comments'), ] operations = [ - migrations.RunPython( - code=update_dashboard_widgets, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_dashboard_widgets, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/migrations/0116_custom_link_button_color.py b/netbox/extras/migrations/0116_custom_link_button_color.py index 665d73017..ff47eab11 100644 --- a/netbox/extras/migrations/0116_custom_link_button_color.py +++ b/netbox/extras/migrations/0116_custom_link_button_color.py @@ -7,7 +7,6 @@ def update_link_buttons(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0115_convert_dashboard_widgets'), ] @@ -18,8 +17,5 @@ class Migration(migrations.Migration): name='button_class', field=models.CharField(default='default', max_length=30), ), - migrations.RunPython( - code=update_link_buttons, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_link_buttons, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/migrations/0117_move_objectchange.py b/netbox/extras/migrations/0117_move_objectchange.py index a69b5a711..62c7255e7 100644 --- a/netbox/extras/migrations/0117_move_objectchange.py +++ b/netbox/extras/migrations/0117_move_objectchange.py @@ -26,7 +26,6 @@ def update_dashboard_widgets(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0116_custom_link_button_color'), ('core', '0011_move_objectchange'), @@ -44,81 +43,64 @@ class Migration(migrations.Migration): name='ObjectChange', table='core_objectchange', ), - # Rename PK sequence - migrations.RunSQL( - "ALTER TABLE extras_objectchange_id_seq" - " RENAME TO core_objectchange_id_seq" - ), - + migrations.RunSQL('ALTER TABLE extras_objectchange_id_seq' ' RENAME TO core_objectchange_id_seq'), # Rename indexes. Hashes generated by schema_editor._create_index_name() + migrations.RunSQL('ALTER INDEX extras_objectchange_pkey' ' RENAME TO core_objectchange_pkey'), migrations.RunSQL( - "ALTER INDEX extras_objectchange_pkey" - " RENAME TO core_objectchange_pkey" + 'ALTER INDEX extras_obje_changed_927fe5_idx' + ' RENAME TO core_objectchange_changed_object_type_id_cha_79a9ed1e' ), migrations.RunSQL( - "ALTER INDEX extras_obje_changed_927fe5_idx" - " RENAME TO core_objectchange_changed_object_type_id_cha_79a9ed1e" + 'ALTER INDEX extras_obje_related_bfcdef_idx' + ' RENAME TO core_objectchange_related_object_type_id_rel_a71d604a' ), migrations.RunSQL( - "ALTER INDEX extras_obje_related_bfcdef_idx" - " RENAME TO core_objectchange_related_object_type_id_rel_a71d604a" + 'ALTER INDEX extras_objectchange_changed_object_type_id_b755bb60' + ' RENAME TO core_objectchange_changed_object_type_id_2070ade6' ), migrations.RunSQL( - "ALTER INDEX extras_objectchange_changed_object_type_id_b755bb60" - " RENAME TO core_objectchange_changed_object_type_id_2070ade6" + 'ALTER INDEX extras_objectchange_related_object_type_id_fe6e521f' + ' RENAME TO core_objectchange_related_object_type_id_b80958af' ), migrations.RunSQL( - "ALTER INDEX extras_objectchange_related_object_type_id_fe6e521f" - " RENAME TO core_objectchange_related_object_type_id_b80958af" + 'ALTER INDEX extras_objectchange_request_id_4ae21e90' + ' RENAME TO core_objectchange_request_id_d9d160ac' ), migrations.RunSQL( - "ALTER INDEX extras_objectchange_request_id_4ae21e90" - " RENAME TO core_objectchange_request_id_d9d160ac" + 'ALTER INDEX extras_objectchange_time_224380ea' ' RENAME TO core_objectchange_time_800f60a5' ), migrations.RunSQL( - "ALTER INDEX extras_objectchange_time_224380ea" - " RENAME TO core_objectchange_time_800f60a5" + 'ALTER INDEX extras_objectchange_user_id_7fdf8186' ' RENAME TO core_objectchange_user_id_2b2142be' ), - migrations.RunSQL( - "ALTER INDEX extras_objectchange_user_id_7fdf8186" - " RENAME TO core_objectchange_user_id_2b2142be" - ), - # Rename constraints migrations.RunSQL( - "ALTER TABLE core_objectchange RENAME CONSTRAINT " - "extras_objectchange_changed_object_id_check TO " - "core_objectchange_changed_object_id_check" + 'ALTER TABLE core_objectchange RENAME CONSTRAINT ' + 'extras_objectchange_changed_object_id_check TO ' + 'core_objectchange_changed_object_id_check' ), migrations.RunSQL( - "ALTER TABLE core_objectchange RENAME CONSTRAINT " - "extras_objectchange_related_object_id_check TO " - "core_objectchange_related_object_id_check" + 'ALTER TABLE core_objectchange RENAME CONSTRAINT ' + 'extras_objectchange_related_object_id_check TO ' + 'core_objectchange_related_object_id_check' ), migrations.RunSQL( - "ALTER TABLE core_objectchange RENAME CONSTRAINT " - "extras_objectchange_changed_object_type__b755bb60_fk_django_co TO " - "core_objectchange_changed_object_type_id_2070ade6" + 'ALTER TABLE core_objectchange RENAME CONSTRAINT ' + 'extras_objectchange_changed_object_type__b755bb60_fk_django_co TO ' + 'core_objectchange_changed_object_type_id_2070ade6' ), migrations.RunSQL( - "ALTER TABLE core_objectchange RENAME CONSTRAINT " - "extras_objectchange_related_object_type__fe6e521f_fk_django_co TO " - "core_objectchange_related_object_type_id_b80958af" + 'ALTER TABLE core_objectchange RENAME CONSTRAINT ' + 'extras_objectchange_related_object_type__fe6e521f_fk_django_co TO ' + 'core_objectchange_related_object_type_id_b80958af' ), migrations.RunSQL( - "ALTER TABLE core_objectchange RENAME CONSTRAINT " - "extras_objectchange_user_id_7fdf8186_fk_auth_user_id TO " - "core_objectchange_user_id_2b2142be" + 'ALTER TABLE core_objectchange RENAME CONSTRAINT ' + 'extras_objectchange_user_id_7fdf8186_fk_auth_user_id TO ' + 'core_objectchange_user_id_2b2142be' ), ], ), - migrations.RunPython( - code=update_content_types, - reverse_code=migrations.RunPython.noop - ), - migrations.RunPython( - code=update_dashboard_widgets, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_content_types, reverse_code=migrations.RunPython.noop), + migrations.RunPython(code=update_dashboard_widgets, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/migrations/0118_customfield_uniqueness.py b/netbox/extras/migrations/0118_customfield_uniqueness.py index b7693aa24..7571e975a 100644 --- a/netbox/extras/migrations/0118_customfield_uniqueness.py +++ b/netbox/extras/migrations/0118_customfield_uniqueness.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0117_move_objectchange'), ] diff --git a/netbox/extras/migrations/0119_notifications.py b/netbox/extras/migrations/0119_notifications.py index c266f3b6c..2e6aefd20 100644 --- a/netbox/extras/migrations/0119_notifications.py +++ b/netbox/extras/migrations/0119_notifications.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('extras', '0118_customfield_uniqueness'), @@ -22,7 +21,10 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=100, unique=True)), ('description', models.CharField(blank=True, max_length=200)), ('groups', models.ManyToManyField(blank=True, related_name='notification_groups', to='users.group')), - ('users', models.ManyToManyField(blank=True, related_name='notification_groups', to=settings.AUTH_USER_MODEL)), + ( + 'users', + models.ManyToManyField(blank=True, related_name='notification_groups', to=settings.AUTH_USER_MODEL), + ), ], options={ 'verbose_name': 'notification group', @@ -36,8 +38,18 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True)), ('object_id', models.PositiveBigIntegerField()), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subscriptions', to=settings.AUTH_USER_MODEL)), + ( + 'object_type', + models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), + ( + 'user', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='subscriptions', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'verbose_name': 'subscription', @@ -53,9 +65,19 @@ class Migration(migrations.Migration): ('read', models.DateTimeField(blank=True, null=True)), ('object_id', models.PositiveBigIntegerField()), ('event_type', models.CharField(max_length=50)), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ( + 'object_type', + models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), ('object_repr', models.CharField(editable=False, max_length=200)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='notifications', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'verbose_name': 'notification', @@ -66,7 +88,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='notification', - constraint=models.UniqueConstraint(fields=('object_type', 'object_id', 'user'), name='extras_notification_unique_per_object_and_user'), + constraint=models.UniqueConstraint( + fields=('object_type', 'object_id', 'user'), name='extras_notification_unique_per_object_and_user' + ), ), migrations.AddIndex( model_name='subscription', @@ -74,6 +98,8 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='subscription', - constraint=models.UniqueConstraint(fields=('object_type', 'object_id', 'user'), name='extras_subscription_unique_per_object_and_user'), + constraint=models.UniqueConstraint( + fields=('object_type', 'object_id', 'user'), name='extras_subscription_unique_per_object_and_user' + ), ), ] diff --git a/netbox/extras/migrations/0120_eventrule_event_types.py b/netbox/extras/migrations/0120_eventrule_event_types.py index f62c83e4c..2bcc0a4e6 100644 --- a/netbox/extras/migrations/0120_eventrule_event_types.py +++ b/netbox/extras/migrations/0120_eventrule_event_types.py @@ -26,7 +26,6 @@ def set_event_types(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0119_notifications'), ] @@ -36,16 +35,10 @@ class Migration(migrations.Migration): model_name='eventrule', name='event_types', field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=50), - blank=True, - null=True, - size=None + base_field=models.CharField(max_length=50), blank=True, null=True, size=None ), ), - migrations.RunPython( - code=set_event_types, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_event_types, reverse_code=migrations.RunPython.noop), migrations.AlterField( model_name='eventrule', name='event_types', diff --git a/netbox/extras/migrations/0121_customfield_related_object_filter.py b/netbox/extras/migrations/0121_customfield_related_object_filter.py index d6e41fd7d..10eecd6cc 100644 --- a/netbox/extras/migrations/0121_customfield_related_object_filter.py +++ b/netbox/extras/migrations/0121_customfield_related_object_filter.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0120_eventrule_event_types'), ] diff --git a/netbox/extras/migrations/0122_charfield_null_choices.py b/netbox/extras/migrations/0122_charfield_null_choices.py index 9a1c7ff3f..a32051cb1 100644 --- a/netbox/extras/migrations/0122_charfield_null_choices.py +++ b/netbox/extras/migrations/0122_charfield_null_choices.py @@ -11,7 +11,6 @@ def set_null_values(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('extras', '0121_customfield_related_object_filter'), ] @@ -22,8 +21,5 @@ class Migration(migrations.Migration): name='base_choices', field=models.CharField(blank=True, max_length=50, null=True), ), - migrations.RunPython( - code=set_null_values, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_null_values, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index d8a274c89..d3e443b14 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -704,7 +704,10 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ExportTemplat def __str__(self): created = timezone.localtime(self.created) - return f"{created.date().isoformat()} {created.time().isoformat(timespec='minutes')} ({self.get_kind_display()})" + return ( + f"{created.date().isoformat()} {created.time().isoformat(timespec='minutes')} " + f"({self.get_kind_display()})" + ) def get_absolute_url(self): return reverse('extras:journalentry', args=[self.pk]) diff --git a/netbox/extras/tests/test_customfields.py b/netbox/extras/tests/test_customfields.py index 2bc9b5acc..ce26cb889 100644 --- a/netbox/extras/tests/test_customfields.py +++ b/netbox/extras/tests/test_customfields.py @@ -637,15 +637,51 @@ class CustomFieldAPITest(APITestCase): ) custom_fields = ( - CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo'), - CustomField(type=CustomFieldTypeChoices.TYPE_LONGTEXT, name='longtext_field', default='ABC'), - CustomField(type=CustomFieldTypeChoices.TYPE_INTEGER, name='integer_field', default=123), - CustomField(type=CustomFieldTypeChoices.TYPE_DECIMAL, name='decimal_field', default=123.45), - CustomField(type=CustomFieldTypeChoices.TYPE_BOOLEAN, name='boolean_field', default=False), - CustomField(type=CustomFieldTypeChoices.TYPE_DATE, name='date_field', default='2020-01-01'), - CustomField(type=CustomFieldTypeChoices.TYPE_DATETIME, name='datetime_field', default='2020-01-01T01:23:45'), - CustomField(type=CustomFieldTypeChoices.TYPE_URL, name='url_field', default='http://example.com/1'), - CustomField(type=CustomFieldTypeChoices.TYPE_JSON, name='json_field', default='{"x": "y"}'), + CustomField( + type=CustomFieldTypeChoices.TYPE_TEXT, + name='text_field', + default='foo' + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_LONGTEXT, + name='longtext_field', + default='ABC' + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_INTEGER, + name='integer_field', + default=123 + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_DECIMAL, + name='decimal_field', + default=123.45 + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_BOOLEAN, + name='boolean_field', + default=False) + , + CustomField( + type=CustomFieldTypeChoices.TYPE_DATE, + name='date_field', + default='2020-01-01' + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_DATETIME, + name='datetime_field', + default='2020-01-01T01:23:45' + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_URL, + name='url_field', + default='http://example.com/1' + ), + CustomField( + type=CustomFieldTypeChoices.TYPE_JSON, + name='json_field', + default='{"x": "y"}' + ), CustomField( type=CustomFieldTypeChoices.TYPE_SELECT, name='select_field', @@ -656,7 +692,7 @@ class CustomFieldAPITest(APITestCase): type=CustomFieldTypeChoices.TYPE_MULTISELECT, name='multiselect_field', default=['foo'], - choice_set=choice_set + choice_set=choice_set, ), CustomField( type=CustomFieldTypeChoices.TYPE_OBJECT, @@ -1273,9 +1309,18 @@ class CustomFieldImportTest(TestCase): Import a Site in CSV format, including a value for each CustomField. """ data = ( - ('name', 'slug', 'status', 'cf_text', 'cf_longtext', 'cf_integer', 'cf_decimal', 'cf_boolean', 'cf_date', 'cf_datetime', 'cf_url', 'cf_json', 'cf_select', 'cf_multiselect'), - ('Site 1', 'site-1', 'active', 'ABC', 'Foo', '123', '123.45', 'True', '2020-01-01', '2020-01-01 12:00:00', 'http://example.com/1', '{"foo": 123}', 'a', '"a,b"'), - ('Site 2', 'site-2', 'active', 'DEF', 'Bar', '456', '456.78', 'False', '2020-01-02', '2020-01-02 12:00:00', 'http://example.com/2', '{"bar": 456}', 'b', '"b,c"'), + ( + 'name', 'slug', 'status', 'cf_text', 'cf_longtext', 'cf_integer', 'cf_decimal', 'cf_boolean', 'cf_date', + 'cf_datetime', 'cf_url', 'cf_json', 'cf_select', 'cf_multiselect', + ), + ( + 'Site 1', 'site-1', 'active', 'ABC', 'Foo', '123', '123.45', 'True', '2020-01-01', + '2020-01-01 12:00:00', 'http://example.com/1', '{"foo": 123}', 'a', '"a,b"', + ), + ( + 'Site 2', 'site-2', 'active', 'DEF', 'Bar', '456', '456.78', 'False', '2020-01-02', + '2020-01-02 12:00:00', 'http://example.com/2', '{"bar": 456}', 'b', '"b,c"', + ), ('Site 3', 'site-3', 'active', '', '', '', '', '', '', '', '', '', '', ''), ) csv_data = '\n'.join(','.join(row) for row in data) @@ -1616,7 +1661,10 @@ class CustomFieldModelFilterTest(TestCase): self.assertEqual(self.filterset({'cf_cf6__lte': ['2016-06-27']}, self.queryset).qs.count(), 2) def test_filter_url_strict(self): - self.assertEqual(self.filterset({'cf_cf7': ['http://a.example.com', 'http://b.example.com']}, self.queryset).qs.count(), 2) + self.assertEqual( + self.filterset({'cf_cf7': ['http://a.example.com', 'http://b.example.com']}, self.queryset).qs.count(), + 2 + ) self.assertEqual(self.filterset({'cf_cf7__n': ['http://b.example.com']}, self.queryset).qs.count(), 2) self.assertEqual(self.filterset({'cf_cf7__ic': ['b']}, self.queryset).qs.count(), 1) self.assertEqual(self.filterset({'cf_cf7__nic': ['b']}, self.queryset).qs.count(), 2) @@ -1640,9 +1688,18 @@ class CustomFieldModelFilterTest(TestCase): def test_filter_object(self): manufacturer_ids = Manufacturer.objects.values_list('id', flat=True) - self.assertEqual(self.filterset({'cf_cf11': [manufacturer_ids[0], manufacturer_ids[1]]}, self.queryset).qs.count(), 2) + self.assertEqual( + self.filterset({'cf_cf11': [manufacturer_ids[0], manufacturer_ids[1]]}, self.queryset).qs.count(), + 2 + ) def test_filter_multiobject(self): manufacturer_ids = Manufacturer.objects.values_list('id', flat=True) - self.assertEqual(self.filterset({'cf_cf12': [manufacturer_ids[0], manufacturer_ids[1]]}, self.queryset).qs.count(), 2) - self.assertEqual(self.filterset({'cf_cf12': [manufacturer_ids[3]]}, self.queryset).qs.count(), 3) + self.assertEqual( + self.filterset({'cf_cf12': [manufacturer_ids[0], manufacturer_ids[1]]}, self.queryset).qs.count(), + 2 + ) + self.assertEqual( + self.filterset({'cf_cf12': [manufacturer_ids[3]]}, self.queryset).qs.count(), + 3 + ) diff --git a/netbox/extras/tests/test_filtersets.py b/netbox/extras/tests/test_filtersets.py index c9eaa3e0e..c94e36e4b 100644 --- a/netbox/extras/tests/test_filtersets.py +++ b/netbox/extras/tests/test_filtersets.py @@ -1135,6 +1135,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): 'l2vpn', 'l2vpntermination', 'location', + 'macaddress', 'manufacturer', 'module', 'modulebay', @@ -1167,6 +1168,8 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): 'tunnelgroup', 'tunneltermination', 'virtualchassis', + 'virtualcircuit', + 'virtualcircuittermination', 'virtualdevicecontext', 'virtualdisk', 'virtualmachine', diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index b13af1db9..32633493f 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -7,128 +7,68 @@ from utilities.urls import get_model_urls app_name = 'extras' urlpatterns = [ - # Custom fields - path('custom-fields/', views.CustomFieldListView.as_view(), name='customfield_list'), - path('custom-fields/add/', views.CustomFieldEditView.as_view(), name='customfield_add'), - path('custom-fields/import/', views.CustomFieldBulkImportView.as_view(), name='customfield_import'), - path('custom-fields/edit/', views.CustomFieldBulkEditView.as_view(), name='customfield_bulk_edit'), - path('custom-fields/delete/', views.CustomFieldBulkDeleteView.as_view(), name='customfield_bulk_delete'), + path('custom-fields/', include(get_model_urls('extras', 'customfield', detail=False))), path('custom-fields//', include(get_model_urls('extras', 'customfield'))), - # Custom field choices - path('custom-field-choices/', views.CustomFieldChoiceSetListView.as_view(), name='customfieldchoiceset_list'), - path('custom-field-choices/add/', views.CustomFieldChoiceSetEditView.as_view(), name='customfieldchoiceset_add'), - path('custom-field-choices/import/', views.CustomFieldChoiceSetBulkImportView.as_view(), name='customfieldchoiceset_import'), - path('custom-field-choices/edit/', views.CustomFieldChoiceSetBulkEditView.as_view(), name='customfieldchoiceset_bulk_edit'), - path('custom-field-choices/delete/', views.CustomFieldChoiceSetBulkDeleteView.as_view(), name='customfieldchoiceset_bulk_delete'), + path('custom-field-choices/', include(get_model_urls('extras', 'customfieldchoiceset', detail=False))), path('custom-field-choices//', include(get_model_urls('extras', 'customfieldchoiceset'))), - # Custom links - path('custom-links/', views.CustomLinkListView.as_view(), name='customlink_list'), - path('custom-links/add/', views.CustomLinkEditView.as_view(), name='customlink_add'), - path('custom-links/import/', views.CustomLinkBulkImportView.as_view(), name='customlink_import'), - path('custom-links/edit/', views.CustomLinkBulkEditView.as_view(), name='customlink_bulk_edit'), - path('custom-links/delete/', views.CustomLinkBulkDeleteView.as_view(), name='customlink_bulk_delete'), + path('custom-links/', include(get_model_urls('extras', 'customlink', detail=False))), path('custom-links//', include(get_model_urls('extras', 'customlink'))), - # Export templates - path('export-templates/', views.ExportTemplateListView.as_view(), name='exporttemplate_list'), - path('export-templates/add/', views.ExportTemplateEditView.as_view(), name='exporttemplate_add'), - path('export-templates/import/', views.ExportTemplateBulkImportView.as_view(), name='exporttemplate_import'), - path('export-templates/edit/', views.ExportTemplateBulkEditView.as_view(), name='exporttemplate_bulk_edit'), - path('export-templates/delete/', views.ExportTemplateBulkDeleteView.as_view(), name='exporttemplate_bulk_delete'), - path('export-templates/sync/', views.ExportTemplateBulkSyncDataView.as_view(), name='exporttemplate_bulk_sync'), + path('export-templates/', include(get_model_urls('extras', 'exporttemplate', detail=False))), path('export-templates//', include(get_model_urls('extras', 'exporttemplate'))), - # Saved filters - path('saved-filters/', views.SavedFilterListView.as_view(), name='savedfilter_list'), - path('saved-filters/add/', views.SavedFilterEditView.as_view(), name='savedfilter_add'), - path('saved-filters/import/', views.SavedFilterBulkImportView.as_view(), name='savedfilter_import'), - path('saved-filters/edit/', views.SavedFilterBulkEditView.as_view(), name='savedfilter_bulk_edit'), - path('saved-filters/delete/', views.SavedFilterBulkDeleteView.as_view(), name='savedfilter_bulk_delete'), + path('saved-filters/', include(get_model_urls('extras', 'savedfilter', detail=False))), path('saved-filters//', include(get_model_urls('extras', 'savedfilter'))), - # Bookmarks - path('bookmarks/add/', views.BookmarkCreateView.as_view(), name='bookmark_add'), - path('bookmarks/delete/', views.BookmarkBulkDeleteView.as_view(), name='bookmark_bulk_delete'), + path('bookmarks/', include(get_model_urls('extras', 'bookmark', detail=False))), path('bookmarks//', include(get_model_urls('extras', 'bookmark'))), - # Notification groups - path('notification-groups/', views.NotificationGroupListView.as_view(), name='notificationgroup_list'), - path('notification-groups/add/', views.NotificationGroupEditView.as_view(), name='notificationgroup_add'), - path('notification-groups/import/', views.NotificationGroupBulkImportView.as_view(), name='notificationgroup_import'), - path('notification-groups/edit/', views.NotificationGroupBulkEditView.as_view(), name='notificationgroup_bulk_edit'), - path('notification-groups/delete/', views.NotificationGroupBulkDeleteView.as_view(), name='notificationgroup_bulk_delete'), + path('notification-groups/', include(get_model_urls('extras', 'notificationgroup', detail=False))), path('notification-groups//', include(get_model_urls('extras', 'notificationgroup'))), - # Notifications path('notifications/', views.NotificationsView.as_view(), name='notifications'), - path('notifications/delete/', views.NotificationBulkDeleteView.as_view(), name='notification_bulk_delete'), + path('notifications/', include(get_model_urls('extras', 'notification', detail=False))), path('notifications//', include(get_model_urls('extras', 'notification'))), - # Subscriptions - path('subscriptions/add/', views.SubscriptionCreateView.as_view(), name='subscription_add'), - path('subscriptions/delete/', views.SubscriptionBulkDeleteView.as_view(), name='subscription_bulk_delete'), + path('subscriptions/', include(get_model_urls('extras', 'subscription', detail=False))), path('subscriptions//', include(get_model_urls('extras', 'subscription'))), - # Webhooks - path('webhooks/', views.WebhookListView.as_view(), name='webhook_list'), - path('webhooks/add/', views.WebhookEditView.as_view(), name='webhook_add'), - path('webhooks/import/', views.WebhookBulkImportView.as_view(), name='webhook_import'), - path('webhooks/edit/', views.WebhookBulkEditView.as_view(), name='webhook_bulk_edit'), - path('webhooks/delete/', views.WebhookBulkDeleteView.as_view(), name='webhook_bulk_delete'), + path('webhooks/', include(get_model_urls('extras', 'webhook', detail=False))), path('webhooks//', include(get_model_urls('extras', 'webhook'))), - # Event rules - path('event-rules/', views.EventRuleListView.as_view(), name='eventrule_list'), - path('event-rules/add/', views.EventRuleEditView.as_view(), name='eventrule_add'), - path('event-rules/import/', views.EventRuleBulkImportView.as_view(), name='eventrule_import'), - path('event-rules/edit/', views.EventRuleBulkEditView.as_view(), name='eventrule_bulk_edit'), - path('event-rules/delete/', views.EventRuleBulkDeleteView.as_view(), name='eventrule_bulk_delete'), + path('event-rules/', include(get_model_urls('extras', 'eventrule', detail=False))), path('event-rules//', include(get_model_urls('extras', 'eventrule'))), - # Tags - path('tags/', views.TagListView.as_view(), name='tag_list'), - path('tags/add/', views.TagEditView.as_view(), name='tag_add'), - path('tags/import/', views.TagBulkImportView.as_view(), name='tag_import'), - path('tags/edit/', views.TagBulkEditView.as_view(), name='tag_bulk_edit'), - path('tags/delete/', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'), + path('tags/', include(get_model_urls('extras', 'tag', detail=False))), path('tags//', include(get_model_urls('extras', 'tag'))), - # Config contexts - path('config-contexts/', views.ConfigContextListView.as_view(), name='configcontext_list'), - path('config-contexts/add/', views.ConfigContextEditView.as_view(), name='configcontext_add'), - path('config-contexts/edit/', views.ConfigContextBulkEditView.as_view(), name='configcontext_bulk_edit'), - path('config-contexts/delete/', views.ConfigContextBulkDeleteView.as_view(), name='configcontext_bulk_delete'), - path('config-contexts/sync/', views.ConfigContextBulkSyncDataView.as_view(), name='configcontext_bulk_sync'), + path('config-contexts/', include(get_model_urls('extras', 'configcontext', detail=False))), path('config-contexts//', include(get_model_urls('extras', 'configcontext'))), - # Config templates - path('config-templates/', views.ConfigTemplateListView.as_view(), name='configtemplate_list'), - path('config-templates/add/', views.ConfigTemplateEditView.as_view(), name='configtemplate_add'), - path('config-templates/edit/', views.ConfigTemplateBulkEditView.as_view(), name='configtemplate_bulk_edit'), - path('config-templates/delete/', views.ConfigTemplateBulkDeleteView.as_view(), name='configtemplate_bulk_delete'), - path('config-templates/sync/', views.ConfigTemplateBulkSyncDataView.as_view(), name='configtemplate_bulk_sync'), + path('config-templates/', include(get_model_urls('extras', 'configtemplate', detail=False))), path('config-templates//', include(get_model_urls('extras', 'configtemplate'))), - # Image attachments - path('image-attachments/', views.ImageAttachmentListView.as_view(), name='imageattachment_list'), - path('image-attachments/add/', views.ImageAttachmentEditView.as_view(), name='imageattachment_add'), + path('image-attachments/', include(get_model_urls('extras', 'imageattachment', detail=False))), path('image-attachments//', include(get_model_urls('extras', 'imageattachment'))), - # Journal entries - path('journal-entries/', views.JournalEntryListView.as_view(), name='journalentry_list'), - path('journal-entries/add/', views.JournalEntryEditView.as_view(), name='journalentry_add'), - path('journal-entries/edit/', views.JournalEntryBulkEditView.as_view(), name='journalentry_bulk_edit'), - path('journal-entries/delete/', views.JournalEntryBulkDeleteView.as_view(), name='journalentry_bulk_delete'), - path('journal-entries/import/', views.JournalEntryBulkImportView.as_view(), name='journalentry_import'), + path('journal-entries/', include(get_model_urls('extras', 'journalentry', detail=False))), path('journal-entries//', include(get_model_urls('extras', 'journalentry'))), # User dashboard path('dashboard/reset/', views.DashboardResetView.as_view(), name='dashboard_reset'), path('dashboard/widgets/add/', views.DashboardWidgetAddView.as_view(), name='dashboardwidget_add'), - path('dashboard/widgets//configure/', views.DashboardWidgetConfigView.as_view(), name='dashboardwidget_config'), - path('dashboard/widgets//delete/', views.DashboardWidgetDeleteView.as_view(), name='dashboardwidget_delete'), + path( + 'dashboard/widgets//configure/', + views.DashboardWidgetConfigView.as_view(), + name='dashboardwidget_config' + ), + path( + 'dashboard/widgets//delete/', + views.DashboardWidgetDeleteView.as_view(), + name='dashboardwidget_delete' + ), # Scripts path('scripts/', views.ScriptListView.as_view(), name='script_list'), diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 0d98b1324..04f29a020 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -42,6 +42,7 @@ from .tables import ReportResultsTable, ScriptResultsTable # Custom fields # +@register_model_view(CustomField, 'list', path='', detail=False) class CustomFieldListView(generic.ObjectListView): queryset = CustomField.objects.select_related('choice_set') filterset = filtersets.CustomFieldFilterSet @@ -69,6 +70,7 @@ class CustomFieldView(generic.ObjectView): } +@register_model_view(CustomField, 'add', detail=False) @register_model_view(CustomField, 'edit') class CustomFieldEditView(generic.ObjectEditView): queryset = CustomField.objects.select_related('choice_set') @@ -80,11 +82,13 @@ class CustomFieldDeleteView(generic.ObjectDeleteView): queryset = CustomField.objects.select_related('choice_set') +@register_model_view(CustomField, 'import', detail=False) class CustomFieldBulkImportView(generic.BulkImportView): queryset = CustomField.objects.select_related('choice_set') model_form = forms.CustomFieldImportForm +@register_model_view(CustomField, 'bulk_edit', path='edit', detail=False) class CustomFieldBulkEditView(generic.BulkEditView): queryset = CustomField.objects.select_related('choice_set') filterset = filtersets.CustomFieldFilterSet @@ -92,6 +96,7 @@ class CustomFieldBulkEditView(generic.BulkEditView): form = forms.CustomFieldBulkEditForm +@register_model_view(CustomField, 'bulk_delete', path='delete', detail=False) class CustomFieldBulkDeleteView(generic.BulkDeleteView): queryset = CustomField.objects.select_related('choice_set') filterset = filtersets.CustomFieldFilterSet @@ -102,6 +107,7 @@ class CustomFieldBulkDeleteView(generic.BulkDeleteView): # Custom field choices # +@register_model_view(CustomFieldChoiceSet, 'list', path='', detail=False) class CustomFieldChoiceSetListView(generic.ObjectListView): queryset = CustomFieldChoiceSet.objects.all() filterset = filtersets.CustomFieldChoiceSetFilterSet @@ -133,6 +139,7 @@ class CustomFieldChoiceSetView(generic.ObjectView): } +@register_model_view(CustomFieldChoiceSet, 'add', detail=False) @register_model_view(CustomFieldChoiceSet, 'edit') class CustomFieldChoiceSetEditView(generic.ObjectEditView): queryset = CustomFieldChoiceSet.objects.all() @@ -144,11 +151,13 @@ class CustomFieldChoiceSetDeleteView(generic.ObjectDeleteView): queryset = CustomFieldChoiceSet.objects.all() +@register_model_view(CustomFieldChoiceSet, 'import', detail=False) class CustomFieldChoiceSetBulkImportView(generic.BulkImportView): queryset = CustomFieldChoiceSet.objects.all() model_form = forms.CustomFieldChoiceSetImportForm +@register_model_view(CustomFieldChoiceSet, 'bulk_edit', path='edit', detail=False) class CustomFieldChoiceSetBulkEditView(generic.BulkEditView): queryset = CustomFieldChoiceSet.objects.all() filterset = filtersets.CustomFieldChoiceSetFilterSet @@ -156,6 +165,7 @@ class CustomFieldChoiceSetBulkEditView(generic.BulkEditView): form = forms.CustomFieldChoiceSetBulkEditForm +@register_model_view(CustomFieldChoiceSet, 'bulk_delete', path='delete', detail=False) class CustomFieldChoiceSetBulkDeleteView(generic.BulkDeleteView): queryset = CustomFieldChoiceSet.objects.all() filterset = filtersets.CustomFieldChoiceSetFilterSet @@ -166,6 +176,7 @@ class CustomFieldChoiceSetBulkDeleteView(generic.BulkDeleteView): # Custom links # +@register_model_view(CustomLink, 'list', path='', detail=False) class CustomLinkListView(generic.ObjectListView): queryset = CustomLink.objects.all() filterset = filtersets.CustomLinkFilterSet @@ -178,6 +189,7 @@ class CustomLinkView(generic.ObjectView): queryset = CustomLink.objects.all() +@register_model_view(CustomLink, 'add', detail=False) @register_model_view(CustomLink, 'edit') class CustomLinkEditView(generic.ObjectEditView): queryset = CustomLink.objects.all() @@ -189,11 +201,13 @@ class CustomLinkDeleteView(generic.ObjectDeleteView): queryset = CustomLink.objects.all() +@register_model_view(CustomLink, 'import', detail=False) class CustomLinkBulkImportView(generic.BulkImportView): queryset = CustomLink.objects.all() model_form = forms.CustomLinkImportForm +@register_model_view(CustomLink, 'bulk_edit', path='edit', detail=False) class CustomLinkBulkEditView(generic.BulkEditView): queryset = CustomLink.objects.all() filterset = filtersets.CustomLinkFilterSet @@ -201,6 +215,7 @@ class CustomLinkBulkEditView(generic.BulkEditView): form = forms.CustomLinkBulkEditForm +@register_model_view(CustomLink, 'bulk_delete', path='delete', detail=False) class CustomLinkBulkDeleteView(generic.BulkDeleteView): queryset = CustomLink.objects.all() filterset = filtersets.CustomLinkFilterSet @@ -211,6 +226,7 @@ class CustomLinkBulkDeleteView(generic.BulkDeleteView): # Export templates # +@register_model_view(ExportTemplate, 'list', path='', detail=False) class ExportTemplateListView(generic.ObjectListView): queryset = ExportTemplate.objects.all() filterset = filtersets.ExportTemplateFilterSet @@ -228,6 +244,7 @@ class ExportTemplateView(generic.ObjectView): queryset = ExportTemplate.objects.all() +@register_model_view(ExportTemplate, 'add', detail=False) @register_model_view(ExportTemplate, 'edit') class ExportTemplateEditView(generic.ObjectEditView): queryset = ExportTemplate.objects.all() @@ -239,11 +256,13 @@ class ExportTemplateDeleteView(generic.ObjectDeleteView): queryset = ExportTemplate.objects.all() +@register_model_view(ExportTemplate, 'import', detail=False) class ExportTemplateBulkImportView(generic.BulkImportView): queryset = ExportTemplate.objects.all() model_form = forms.ExportTemplateImportForm +@register_model_view(ExportTemplate, 'bulk_edit', path='edit', detail=False) class ExportTemplateBulkEditView(generic.BulkEditView): queryset = ExportTemplate.objects.all() filterset = filtersets.ExportTemplateFilterSet @@ -251,12 +270,14 @@ class ExportTemplateBulkEditView(generic.BulkEditView): form = forms.ExportTemplateBulkEditForm +@register_model_view(ExportTemplate, 'bulk_delete', path='delete', detail=False) class ExportTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ExportTemplate.objects.all() filterset = filtersets.ExportTemplateFilterSet table = tables.ExportTemplateTable +@register_model_view(ExportTemplate, 'bulk_sync', path='sync', detail=False) class ExportTemplateBulkSyncDataView(generic.BulkSyncDataView): queryset = ExportTemplate.objects.all() @@ -283,6 +304,7 @@ class SavedFilterMixin: ) +@register_model_view(SavedFilter, 'list', path='', detail=False) class SavedFilterListView(SavedFilterMixin, generic.ObjectListView): filterset = filtersets.SavedFilterFilterSet filterset_form = forms.SavedFilterFilterForm @@ -294,6 +316,7 @@ class SavedFilterView(SavedFilterMixin, generic.ObjectView): queryset = SavedFilter.objects.all() +@register_model_view(SavedFilter, 'add', detail=False) @register_model_view(SavedFilter, 'edit') class SavedFilterEditView(SavedFilterMixin, generic.ObjectEditView): queryset = SavedFilter.objects.all() @@ -310,11 +333,13 @@ class SavedFilterDeleteView(SavedFilterMixin, generic.ObjectDeleteView): queryset = SavedFilter.objects.all() +@register_model_view(SavedFilter, 'import', detail=False) class SavedFilterBulkImportView(SavedFilterMixin, generic.BulkImportView): queryset = SavedFilter.objects.all() model_form = forms.SavedFilterImportForm +@register_model_view(SavedFilter, 'bulk_edit', path='edit', detail=False) class SavedFilterBulkEditView(SavedFilterMixin, generic.BulkEditView): queryset = SavedFilter.objects.all() filterset = filtersets.SavedFilterFilterSet @@ -322,6 +347,7 @@ class SavedFilterBulkEditView(SavedFilterMixin, generic.BulkEditView): form = forms.SavedFilterBulkEditForm +@register_model_view(SavedFilter, 'bulk_delete', path='delete', detail=False) class SavedFilterBulkDeleteView(SavedFilterMixin, generic.BulkDeleteView): queryset = SavedFilter.objects.all() filterset = filtersets.SavedFilterFilterSet @@ -332,6 +358,7 @@ class SavedFilterBulkDeleteView(SavedFilterMixin, generic.BulkDeleteView): # Bookmarks # +@register_model_view(Bookmark, 'add', detail=False) class BookmarkCreateView(generic.ObjectEditView): form = forms.BookmarkForm @@ -350,6 +377,7 @@ class BookmarkDeleteView(generic.ObjectDeleteView): return Bookmark.objects.filter(user=request.user) +@register_model_view(Bookmark, 'bulk_delete', path='delete', detail=False) class BookmarkBulkDeleteView(generic.BulkDeleteView): table = tables.BookmarkTable @@ -361,6 +389,7 @@ class BookmarkBulkDeleteView(generic.BulkDeleteView): # Notification groups # +@register_model_view(NotificationGroup, 'list', path='', detail=False) class NotificationGroupListView(generic.ObjectListView): queryset = NotificationGroup.objects.all() filterset = filtersets.NotificationGroupFilterSet @@ -373,6 +402,7 @@ class NotificationGroupView(generic.ObjectView): queryset = NotificationGroup.objects.all() +@register_model_view(NotificationGroup, 'add', detail=False) @register_model_view(NotificationGroup, 'edit') class NotificationGroupEditView(generic.ObjectEditView): queryset = NotificationGroup.objects.all() @@ -384,11 +414,13 @@ class NotificationGroupDeleteView(generic.ObjectDeleteView): queryset = NotificationGroup.objects.all() +@register_model_view(NotificationGroup, 'import', detail=False) class NotificationGroupBulkImportView(generic.BulkImportView): queryset = NotificationGroup.objects.all() model_form = forms.NotificationGroupImportForm +@register_model_view(NotificationGroup, 'bulk_edit', path='edit', detail=False) class NotificationGroupBulkEditView(generic.BulkEditView): queryset = NotificationGroup.objects.all() filterset = filtersets.NotificationGroupFilterSet @@ -396,6 +428,7 @@ class NotificationGroupBulkEditView(generic.BulkEditView): form = forms.NotificationGroupBulkEditForm +@register_model_view(NotificationGroup, 'bulk_delete', path='delete', detail=False) class NotificationGroupBulkDeleteView(generic.BulkDeleteView): queryset = NotificationGroup.objects.all() filterset = filtersets.NotificationGroupFilterSet @@ -459,6 +492,7 @@ class NotificationDeleteView(generic.ObjectDeleteView): return Notification.objects.filter(user=request.user) +@register_model_view(Notification, 'bulk_delete', path='delete', detail=False) class NotificationBulkDeleteView(generic.BulkDeleteView): table = tables.NotificationTable @@ -470,6 +504,7 @@ class NotificationBulkDeleteView(generic.BulkDeleteView): # Subscriptions # +@register_model_view(Subscription, 'add', detail=False) class SubscriptionCreateView(generic.ObjectEditView): form = forms.SubscriptionForm @@ -488,6 +523,7 @@ class SubscriptionDeleteView(generic.ObjectDeleteView): return Subscription.objects.filter(user=request.user) +@register_model_view(Subscription, 'bulk_delete', path='delete', detail=False) class SubscriptionBulkDeleteView(generic.BulkDeleteView): table = tables.SubscriptionTable @@ -499,6 +535,7 @@ class SubscriptionBulkDeleteView(generic.BulkDeleteView): # Webhooks # +@register_model_view(Webhook, 'list', path='', detail=False) class WebhookListView(generic.ObjectListView): queryset = Webhook.objects.all() filterset = filtersets.WebhookFilterSet @@ -511,6 +548,7 @@ class WebhookView(generic.ObjectView): queryset = Webhook.objects.all() +@register_model_view(Webhook, 'add', detail=False) @register_model_view(Webhook, 'edit') class WebhookEditView(generic.ObjectEditView): queryset = Webhook.objects.all() @@ -522,11 +560,13 @@ class WebhookDeleteView(generic.ObjectDeleteView): queryset = Webhook.objects.all() +@register_model_view(Webhook, 'import', detail=False) class WebhookBulkImportView(generic.BulkImportView): queryset = Webhook.objects.all() model_form = forms.WebhookImportForm +@register_model_view(Webhook, 'bulk_edit', path='edit', detail=False) class WebhookBulkEditView(generic.BulkEditView): queryset = Webhook.objects.all() filterset = filtersets.WebhookFilterSet @@ -534,6 +574,7 @@ class WebhookBulkEditView(generic.BulkEditView): form = forms.WebhookBulkEditForm +@register_model_view(Webhook, 'bulk_delete', path='delete', detail=False) class WebhookBulkDeleteView(generic.BulkDeleteView): queryset = Webhook.objects.all() filterset = filtersets.WebhookFilterSet @@ -544,6 +585,7 @@ class WebhookBulkDeleteView(generic.BulkDeleteView): # Event Rules # +@register_model_view(EventRule, 'list', path='', detail=False) class EventRuleListView(generic.ObjectListView): queryset = EventRule.objects.all() filterset = filtersets.EventRuleFilterSet @@ -556,6 +598,7 @@ class EventRuleView(generic.ObjectView): queryset = EventRule.objects.all() +@register_model_view(EventRule, 'add', detail=False) @register_model_view(EventRule, 'edit') class EventRuleEditView(generic.ObjectEditView): queryset = EventRule.objects.all() @@ -567,11 +610,13 @@ class EventRuleDeleteView(generic.ObjectDeleteView): queryset = EventRule.objects.all() +@register_model_view(EventRule, 'import', detail=False) class EventRuleBulkImportView(generic.BulkImportView): queryset = EventRule.objects.all() model_form = forms.EventRuleImportForm +@register_model_view(EventRule, 'bulk_edit', path='edit', detail=False) class EventRuleBulkEditView(generic.BulkEditView): queryset = EventRule.objects.all() filterset = filtersets.EventRuleFilterSet @@ -579,6 +624,7 @@ class EventRuleBulkEditView(generic.BulkEditView): form = forms.EventRuleBulkEditForm +@register_model_view(EventRule, 'bulk_delete', path='delete', detail=False) class EventRuleBulkDeleteView(generic.BulkDeleteView): queryset = EventRule.objects.all() filterset = filtersets.EventRuleFilterSet @@ -589,6 +635,7 @@ class EventRuleBulkDeleteView(generic.BulkDeleteView): # Tags # +@register_model_view(Tag, 'list', path='', detail=False) class TagListView(generic.ObjectListView): queryset = Tag.objects.annotate( items=count_related(TaggedItem, 'tag') @@ -624,6 +671,7 @@ class TagView(generic.ObjectView): } +@register_model_view(Tag, 'add', detail=False) @register_model_view(Tag, 'edit') class TagEditView(generic.ObjectEditView): queryset = Tag.objects.all() @@ -635,11 +683,13 @@ class TagDeleteView(generic.ObjectDeleteView): queryset = Tag.objects.all() +@register_model_view(Tag, 'import', detail=False) class TagBulkImportView(generic.BulkImportView): queryset = Tag.objects.all() model_form = forms.TagImportForm +@register_model_view(Tag, 'bulk_edit', path='edit', detail=False) class TagBulkEditView(generic.BulkEditView): queryset = Tag.objects.annotate( items=count_related(TaggedItem, 'tag') @@ -648,6 +698,7 @@ class TagBulkEditView(generic.BulkEditView): form = forms.TagBulkEditForm +@register_model_view(Tag, 'bulk_delete', path='delete', detail=False) class TagBulkDeleteView(generic.BulkDeleteView): queryset = Tag.objects.annotate( items=count_related(TaggedItem, 'tag') @@ -659,6 +710,7 @@ class TagBulkDeleteView(generic.BulkDeleteView): # Config contexts # +@register_model_view(ConfigContext, 'list', path='', detail=False) class ConfigContextListView(generic.ObjectListView): queryset = ConfigContext.objects.all() filterset = filtersets.ConfigContextFilterSet @@ -711,30 +763,34 @@ class ConfigContextView(generic.ObjectView): } +@register_model_view(ConfigContext, 'add', detail=False) @register_model_view(ConfigContext, 'edit') class ConfigContextEditView(generic.ObjectEditView): queryset = ConfigContext.objects.all() form = forms.ConfigContextForm -class ConfigContextBulkEditView(generic.BulkEditView): - queryset = ConfigContext.objects.all() - filterset = filtersets.ConfigContextFilterSet - table = tables.ConfigContextTable - form = forms.ConfigContextBulkEditForm - - @register_model_view(ConfigContext, 'delete') class ConfigContextDeleteView(generic.ObjectDeleteView): queryset = ConfigContext.objects.all() +@register_model_view(ConfigContext, 'bulk_edit', path='edit', detail=False) +class ConfigContextBulkEditView(generic.BulkEditView): + queryset = ConfigContext.objects.all() + filterset = filtersets.ConfigContextFilterSet + table = tables.ConfigContextTable + form = forms.ConfigContextBulkEditForm + + +@register_model_view(ConfigContext, 'bulk_delete', path='delete', detail=False) class ConfigContextBulkDeleteView(generic.BulkDeleteView): queryset = ConfigContext.objects.all() filterset = filtersets.ConfigContextFilterSet table = tables.ConfigContextTable +@register_model_view(ConfigContext, 'bulk_sync', path='sync', detail=False) class ConfigContextBulkSyncDataView(generic.BulkSyncDataView): queryset = ConfigContext.objects.all() @@ -768,6 +824,7 @@ class ObjectConfigContextView(generic.ObjectView): # Config templates # +@register_model_view(ConfigTemplate, 'list', path='', detail=False) class ConfigTemplateListView(generic.ObjectListView): queryset = ConfigTemplate.objects.annotate( device_count=count_related(Device, 'config_template'), @@ -790,6 +847,7 @@ class ConfigTemplateView(generic.ObjectView): queryset = ConfigTemplate.objects.all() +@register_model_view(ConfigTemplate, 'add', detail=False) @register_model_view(ConfigTemplate, 'edit') class ConfigTemplateEditView(generic.ObjectEditView): queryset = ConfigTemplate.objects.all() @@ -801,11 +859,13 @@ class ConfigTemplateDeleteView(generic.ObjectDeleteView): queryset = ConfigTemplate.objects.all() +@register_model_view(ConfigTemplate, 'import', detail=False) class ConfigTemplateBulkImportView(generic.BulkImportView): queryset = ConfigTemplate.objects.all() model_form = forms.ConfigTemplateImportForm +@register_model_view(ConfigTemplate, 'bulk_edit', path='edit', detail=False) class ConfigTemplateBulkEditView(generic.BulkEditView): queryset = ConfigTemplate.objects.all() filterset = filtersets.ConfigTemplateFilterSet @@ -813,12 +873,14 @@ class ConfigTemplateBulkEditView(generic.BulkEditView): form = forms.ConfigTemplateBulkEditForm +@register_model_view(ConfigTemplate, 'bulk_delete', path='delete', detail=False) class ConfigTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ConfigTemplate.objects.all() filterset = filtersets.ConfigTemplateFilterSet table = tables.ConfigTemplateTable +@register_model_view(ConfigTemplate, 'bulk_sync', path='sync', detail=False) class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView): queryset = ConfigTemplate.objects.all() @@ -827,6 +889,7 @@ class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView): # Image attachments # +@register_model_view(ImageAttachment, 'list', path='', detail=False) class ImageAttachmentListView(generic.ObjectListView): queryset = ImageAttachment.objects.all() filterset = filtersets.ImageAttachmentFilterSet @@ -837,6 +900,7 @@ class ImageAttachmentListView(generic.ObjectListView): } +@register_model_view(ImageAttachment, 'add', detail=False) @register_model_view(ImageAttachment, 'edit') class ImageAttachmentEditView(generic.ObjectEditView): queryset = ImageAttachment.objects.all() @@ -871,6 +935,7 @@ class ImageAttachmentDeleteView(generic.ObjectDeleteView): # Journal entries # +@register_model_view(JournalEntry, 'list', path='', detail=False) class JournalEntryListView(generic.ObjectListView): queryset = JournalEntry.objects.all() filterset = filtersets.JournalEntryFilterSet @@ -889,6 +954,7 @@ class JournalEntryView(generic.ObjectView): queryset = JournalEntry.objects.all() +@register_model_view(JournalEntry, 'add', detail=False) @register_model_view(JournalEntry, 'edit') class JournalEntryEditView(generic.ObjectEditView): queryset = JournalEntry.objects.all() @@ -917,6 +983,13 @@ class JournalEntryDeleteView(generic.ObjectDeleteView): return reverse(viewname, kwargs={'pk': obj.pk}) +@register_model_view(JournalEntry, 'import', detail=False) +class JournalEntryBulkImportView(generic.BulkImportView): + queryset = JournalEntry.objects.all() + model_form = forms.JournalEntryImportForm + + +@register_model_view(JournalEntry, 'bulk_edit', path='edit', detail=False) class JournalEntryBulkEditView(generic.BulkEditView): queryset = JournalEntry.objects.all() filterset = filtersets.JournalEntryFilterSet @@ -924,17 +997,13 @@ class JournalEntryBulkEditView(generic.BulkEditView): form = forms.JournalEntryBulkEditForm +@register_model_view(JournalEntry, 'bulk_delete', path='delete', detail=False) class JournalEntryBulkDeleteView(generic.BulkDeleteView): queryset = JournalEntry.objects.all() filterset = filtersets.JournalEntryFilterSet table = tables.JournalEntryTable -class JournalEntryBulkImportView(generic.BulkImportView): - queryset = JournalEntry.objects.all() - model_form = forms.JournalEntryImportForm - - # # Dashboard & widgets # @@ -1181,7 +1250,6 @@ class ScriptView(BaseScriptView): request=copy_safe_request(request), job_timeout=script.python_class.job_timeout, commit=form.cleaned_data.pop('_commit'), - name=script.name ) return redirect('extras:script_result', job_pk=job.pk) diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index 56a6dc3d9..094da3007 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -109,7 +109,8 @@ class RIRForm(NetBoxModelForm): class AggregateForm(TenancyForm, NetBoxModelForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), - label=_('RIR') + label=_('RIR'), + quick_add=True ) comments = CommentField() @@ -132,6 +133,7 @@ class ASNRangeForm(TenancyForm, NetBoxModelForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), label=_('RIR'), + quick_add=True ) slug = SlugField() fieldsets = ( @@ -150,6 +152,7 @@ class ASNForm(TenancyForm, NetBoxModelForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), label=_('RIR'), + quick_add=True ) sites = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), @@ -216,7 +219,8 @@ class PrefixForm(TenancyForm, ScopedForm, NetBoxModelForm): role = DynamicModelChoiceField( label=_('Role'), queryset=Role.objects.all(), - required=False + required=False, + quick_add=True ) comments = CommentField() @@ -246,7 +250,8 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): role = DynamicModelChoiceField( label=_('Role'), queryset=Role.objects.all(), - required=False + required=False, + quick_add=True ) comments = CommentField() @@ -382,7 +387,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): }) elif selected_objects: assigned_object = self.cleaned_data[selected_objects[0]] - if self.instance.pk and self.instance.assigned_object and self.cleaned_data['primary_for_parent'] and assigned_object != self.instance.assigned_object: + if ( + self.instance.pk and + self.instance.assigned_object and + self.cleaned_data['primary_for_parent'] and + assigned_object != self.instance.assigned_object + ): raise ValidationError( _("Cannot reassign IP address while it is designated as the primary IP for the parent object") ) @@ -639,7 +649,8 @@ class VLANForm(TenancyForm, NetBoxModelForm): role = DynamicModelChoiceField( label=_('Role'), queryset=Role.objects.all(), - required=False + required=False, + quick_add=True ) qinq_svlan = DynamicModelChoiceField( label=_('Q-in-Q SVLAN'), diff --git a/netbox/ipam/graphql/types.py b/netbox/ipam/graphql/types.py index 5a4813e0c..e6ecca984 100644 --- a/netbox/ipam/graphql/types.py +++ b/netbox/ipam/graphql/types.py @@ -295,7 +295,10 @@ class VLANTranslationPolicyType(NetBoxObjectType): filters=VLANTranslationRuleFilter ) class VLANTranslationRuleType(NetBoxObjectType): - policy: Annotated["VLANTranslationPolicyType", strawberry.lazy('ipam.graphql.types')] = strawberry_django.field(select_related=["policy"]) + policy: Annotated[ + "VLANTranslationPolicyType", + strawberry.lazy('ipam.graphql.types') + ] = strawberry_django.field(select_related=["policy"]) @strawberry_django.type( diff --git a/netbox/ipam/migrations/0001_squashed.py b/netbox/ipam/migrations/0001_squashed.py index bef36e698..896d7c4c9 100644 --- a/netbox/ipam/migrations/0001_squashed.py +++ b/netbox/ipam/migrations/0001_squashed.py @@ -9,7 +9,6 @@ import taggit.managers class Migration(migrations.Migration): - initial = True dependencies = [ @@ -50,7 +49,23 @@ class Migration(migrations.Migration): ('status', models.CharField(default='active', max_length=50)), ('role', models.CharField(blank=True, max_length=50)), ('assigned_object_id', models.PositiveIntegerField(blank=True, null=True)), - ('dns_name', models.CharField(blank=True, max_length=255, validators=[django.core.validators.RegexValidator(code='invalid', message='Only alphanumeric characters, asterisks, hyphens, periods, and underscores are allowed in DNS names', regex='^([0-9A-Za-z_-]+|\\*)(\\.[0-9A-Za-z_-]+)*\\.?$')])), + ( + 'dns_name', + models.CharField( + blank=True, + max_length=255, + validators=[ + django.core.validators.RegexValidator( + code='invalid', + message=( + 'Only alphanumeric characters, asterisks, hyphens, periods, and underscores are ' + 'allowed in DNS names' + ), + regex='^([0-9A-Za-z_-]+|\\*)(\\.[0-9A-Za-z_-]+)*\\.?$', + ) + ], + ), + ), ('description', models.CharField(blank=True, max_length=200)), ], options={ @@ -73,7 +88,11 @@ class Migration(migrations.Migration): ], options={ 'verbose_name_plural': 'prefixes', - 'ordering': (django.db.models.expressions.OrderBy(django.db.models.expressions.F('vrf'), nulls_first=True), 'prefix', 'pk'), + 'ordering': ( + django.db.models.expressions.OrderBy(django.db.models.expressions.F('vrf'), nulls_first=True), + 'prefix', + 'pk', + ), }, ), migrations.CreateModel( @@ -135,10 +154,25 @@ class Migration(migrations.Migration): ('rd', models.CharField(blank=True, max_length=21, null=True, unique=True)), ('enforce_unique', models.BooleanField(default=True)), ('description', models.CharField(blank=True, max_length=200)), - ('export_targets', models.ManyToManyField(blank=True, related_name='exporting_vrfs', to='ipam.RouteTarget')), - ('import_targets', models.ManyToManyField(blank=True, related_name='importing_vrfs', to='ipam.RouteTarget')), + ( + 'export_targets', + models.ManyToManyField(blank=True, related_name='exporting_vrfs', to='ipam.RouteTarget'), + ), + ( + 'import_targets', + models.ManyToManyField(blank=True, related_name='importing_vrfs', to='ipam.RouteTarget'), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vrfs', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vrfs', + to='tenancy.tenant', + ), + ), ], options={ 'verbose_name': 'VRF', @@ -157,7 +191,21 @@ class Migration(migrations.Migration): ('slug', models.SlugField(max_length=100)), ('scope_id', models.PositiveBigIntegerField(blank=True, null=True)), ('description', models.CharField(blank=True, max_length=200)), - ('scope_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(('model__in', ('region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster'))), null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ( + 'scope_type', + models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + ( + 'model__in', + ('region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster'), + ) + ), + null=True, + on_delete=django.db.models.deletion.CASCADE, + to='contenttypes.contenttype', + ), + ), ], options={ 'verbose_name': 'VLAN group', @@ -172,15 +220,59 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)), ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('vid', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4094)])), + ( + 'vid', + models.PositiveSmallIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(4094), + ] + ), + ), ('name', models.CharField(max_length=64)), ('status', models.CharField(default='active', max_length=50)), ('description', models.CharField(blank=True, max_length=200)), - ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vlans', to='ipam.vlangroup')), - ('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='vlans', to='ipam.role')), - ('site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vlans', to='dcim.site')), + ( + 'group', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vlans', + to='ipam.vlangroup', + ), + ), + ( + 'role', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='vlans', + to='ipam.role', + ), + ), + ( + 'site', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vlans', + to='dcim.site', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vlans', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vlans', + to='tenancy.tenant', + ), + ), ], options={ 'verbose_name': 'VLAN', @@ -197,9 +289,29 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=100)), ('protocol', models.CharField(max_length=50)), - ('ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(65535)]), size=None)), + ( + 'ports', + django.contrib.postgres.fields.ArrayField( + base_field=models.PositiveIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(65535), + ] + ), + size=None, + ), + ), ('description', models.CharField(blank=True, max_length=200)), - ('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='services', to='dcim.device')), + ( + 'device', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='services', + to='dcim.device', + ), + ), ('ipaddresses', models.ManyToManyField(blank=True, related_name='services', to='ipam.IPAddress')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], diff --git a/netbox/ipam/migrations/0002_squashed_0046.py b/netbox/ipam/migrations/0002_squashed_0046.py index 06bcd8741..6c03753d8 100644 --- a/netbox/ipam/migrations/0002_squashed_0046.py +++ b/netbox/ipam/migrations/0002_squashed_0046.py @@ -4,7 +4,6 @@ import taggit.managers class Migration(migrations.Migration): - dependencies = [ ('dcim', '0003_auto_20160628_1721'), ('virtualization', '0001_virtualization'), @@ -66,7 +65,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='service', name='virtual_machine', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='services', to='virtualization.virtualmachine'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='services', + to='virtualization.virtualmachine', + ), ), migrations.AddField( model_name='routetarget', @@ -76,17 +81,35 @@ class Migration(migrations.Migration): migrations.AddField( model_name='routetarget', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='route_targets', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='route_targets', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='prefix', name='role', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='prefixes', to='ipam.role'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='prefixes', + to='ipam.role', + ), ), migrations.AddField( model_name='prefix', name='site', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='prefixes', to='dcim.site'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='prefixes', + to='dcim.site', + ), ), migrations.AddField( model_name='prefix', @@ -96,27 +119,64 @@ class Migration(migrations.Migration): migrations.AddField( model_name='prefix', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='prefixes', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='prefixes', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='prefix', name='vlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='prefixes', to='ipam.vlan'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='prefixes', + to='ipam.vlan', + ), ), migrations.AddField( model_name='prefix', name='vrf', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='prefixes', to='ipam.vrf'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='prefixes', + to='ipam.vrf', + ), ), migrations.AddField( model_name='ipaddress', name='assigned_object_type', - field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), _connector='OR')), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'dcim'), ('model', 'interface')), + models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), + _connector='OR', + ) + ), + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.AddField( model_name='ipaddress', name='nat_inside', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='nat_outside', to='ipam.ipaddress'), + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='nat_outside', + to='ipam.ipaddress', + ), ), migrations.AddField( model_name='ipaddress', @@ -126,17 +186,31 @@ class Migration(migrations.Migration): migrations.AddField( model_name='ipaddress', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='ip_addresses', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='ip_addresses', + to='tenancy.tenant', + ), ), migrations.AddField( model_name='ipaddress', name='vrf', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='ip_addresses', to='ipam.vrf'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='ip_addresses', + to='ipam.vrf', + ), ), migrations.AddField( model_name='aggregate', name='rir', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='aggregates', to='ipam.rir'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='aggregates', to='ipam.rir' + ), ), migrations.AddField( model_name='aggregate', @@ -146,7 +220,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='aggregate', name='tenant', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='aggregates', to='tenancy.tenant'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='aggregates', + to='tenancy.tenant', + ), ), migrations.AlterUniqueTogether( name='vlangroup', diff --git a/netbox/ipam/migrations/0047_squashed_0053.py b/netbox/ipam/migrations/0047_squashed_0053.py index 470261316..a05d0cb81 100644 --- a/netbox/ipam/migrations/0047_squashed_0053.py +++ b/netbox/ipam/migrations/0047_squashed_0053.py @@ -8,7 +8,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('ipam', '0047_prefix_depth_children'), ('ipam', '0048_prefix_populate_depth_children'), @@ -16,7 +15,7 @@ class Migration(migrations.Migration): ('ipam', '0050_iprange'), ('ipam', '0051_extend_tag_support'), ('ipam', '0052_fhrpgroup'), - ('ipam', '0053_asn_model') + ('ipam', '0053_asn_model'), ] dependencies = [ @@ -47,17 +46,47 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('start_address', ipam.fields.IPAddressField()), ('end_address', ipam.fields.IPAddressField()), ('size', models.PositiveIntegerField(editable=False)), ('status', models.CharField(default='active', max_length=50)), ('description', models.CharField(blank=True, max_length=200)), - ('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ip_ranges', to='ipam.role')), + ( + 'role', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='ip_ranges', + to='ipam.role', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='ip_ranges', to='tenancy.tenant')), - ('vrf', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='ip_ranges', to='ipam.vrf')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='ip_ranges', + to='tenancy.tenant', + ), + ), + ( + 'vrf', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='ip_ranges', + to='ipam.vrf', + ), + ), ], options={ 'verbose_name': 'IP range', @@ -85,7 +114,10 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('group_id', models.PositiveSmallIntegerField()), ('protocol', models.CharField(max_length=50)), @@ -102,7 +134,21 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='ipaddress', name='assigned_object_type', - field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'ipam'), ('model', 'fhrpgroup')), models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), _connector='OR')), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'), + field=models.ForeignKey( + blank=True, + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'dcim'), ('model', 'interface')), + models.Q(('app_label', 'ipam'), ('model', 'fhrpgroup')), + models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), + _connector='OR', + ) + ), + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), ), migrations.CreateModel( name='FHRPGroupAssignment', @@ -111,9 +157,20 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('interface_id', models.PositiveIntegerField()), - ('priority', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(255)])), + ( + 'priority', + models.PositiveSmallIntegerField( + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MaxValueValidator(255), + ] + ), + ), ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ipam.fhrpgroup')), - ('interface_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ( + 'interface_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), ], options={ 'verbose_name': 'FHRP group assignment', @@ -126,13 +183,28 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(primary_key=True, serialize=False)), ('asn', ipam.fields.ASNField(unique=True)), ('description', models.CharField(blank=True, max_length=200)), - ('rir', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='asns', to='ipam.rir')), + ( + 'rir', + models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='asns', to='ipam.rir'), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='asns', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='asns', + to='tenancy.tenant', + ), + ), ], options={ 'verbose_name': 'ASN', diff --git a/netbox/ipam/migrations/0054_squashed_0067.py b/netbox/ipam/migrations/0054_squashed_0067.py index 40073ca29..929a27fda 100644 --- a/netbox/ipam/migrations/0054_squashed_0067.py +++ b/netbox/ipam/migrations/0054_squashed_0067.py @@ -10,7 +10,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('ipam', '0054_vlangroup_min_max_vids'), ('ipam', '0055_servicetemplate'), @@ -25,7 +24,7 @@ class Migration(migrations.Migration): ('ipam', '0064_clear_search_cache'), ('ipam', '0065_asnrange'), ('ipam', '0066_iprange_mark_utilized'), - ('ipam', '0067_ipaddress_index_host') + ('ipam', '0067_ipaddress_index_host'), ] dependencies = [ @@ -40,12 +39,24 @@ class Migration(migrations.Migration): migrations.AddField( model_name='vlangroup', name='max_vid', - field=models.PositiveSmallIntegerField(default=4094, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4094)]), + field=models.PositiveSmallIntegerField( + default=4094, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(4094), + ], + ), ), migrations.AddField( model_name='vlangroup', name='min_vid', - field=models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4094)]), + field=models.PositiveSmallIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(4094), + ], + ), ), migrations.AlterField( model_name='aggregate', @@ -187,10 +198,24 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('protocol', models.CharField(max_length=50)), - ('ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(65535)]), size=None)), + ( + 'ports', + django.contrib.postgres.fields.ArrayField( + base_field=models.PositiveIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(65535), + ] + ), + size=None, + ), + ), ('description', models.CharField(blank=True, max_length=200)), ('name', models.CharField(max_length=100, unique=True)), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), @@ -217,7 +242,13 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='ipaddress', name='nat_inside', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='nat_outside', to='ipam.ipaddress'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='nat_outside', + to='ipam.ipaddress', + ), ), migrations.CreateModel( name='L2VPN', @@ -225,16 +256,34 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('name', models.CharField(max_length=100, unique=True)), ('slug', models.SlugField(max_length=100, unique=True)), ('type', models.CharField(max_length=50)), ('identifier', models.BigIntegerField(blank=True, null=True)), ('description', models.CharField(blank=True, max_length=200)), - ('export_targets', models.ManyToManyField(blank=True, related_name='exporting_l2vpns', to='ipam.routetarget')), - ('import_targets', models.ManyToManyField(blank=True, related_name='importing_l2vpns', to='ipam.routetarget')), + ( + 'export_targets', + models.ManyToManyField(blank=True, related_name='exporting_l2vpns', to='ipam.routetarget'), + ), + ( + 'import_targets', + models.ManyToManyField(blank=True, related_name='importing_l2vpns', to='ipam.routetarget'), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='l2vpns', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='l2vpns', + to='tenancy.tenant', + ), + ), ], options={ 'verbose_name': 'L2VPN', @@ -247,10 +296,33 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('assigned_object_id', models.PositiveBigIntegerField()), - ('assigned_object_type', models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'ipam'), ('model', 'vlan')), models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), - ('l2vpn', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='ipam.l2vpn')), + ( + 'assigned_object_type', + models.ForeignKey( + limit_choices_to=models.Q( + models.Q( + models.Q(('app_label', 'dcim'), ('model', 'interface')), + models.Q(('app_label', 'ipam'), ('model', 'vlan')), + models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), + _connector='OR', + ) + ), + on_delete=django.db.models.deletion.PROTECT, + related_name='+', + to='contenttypes.contenttype', + ), + ), + ( + 'l2vpn', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='ipam.l2vpn' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -260,7 +332,9 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='l2vpntermination', - constraint=models.UniqueConstraint(fields=('assigned_object_type', 'assigned_object_id'), name='ipam_l2vpntermination_assigned_object'), + constraint=models.UniqueConstraint( + fields=('assigned_object_type', 'assigned_object_id'), name='ipam_l2vpntermination_assigned_object' + ), ), migrations.AddField( model_name='fhrpgroup', @@ -281,7 +355,10 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='fhrpgroupassignment', - constraint=models.UniqueConstraint(fields=('interface_type', 'interface_id', 'group'), name='ipam_fhrpgroupassignment_unique_interface_group'), + constraint=models.UniqueConstraint( + fields=('interface_type', 'interface_id', 'group'), + name='ipam_fhrpgroupassignment_unique_interface_group', + ), ), migrations.AddConstraint( model_name='vlan', @@ -293,11 +370,15 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='vlangroup', - constraint=models.UniqueConstraint(fields=('scope_type', 'scope_id', 'name'), name='ipam_vlangroup_unique_scope_name'), + constraint=models.UniqueConstraint( + fields=('scope_type', 'scope_id', 'name'), name='ipam_vlangroup_unique_scope_name' + ), ), migrations.AddConstraint( model_name='vlangroup', - constraint=models.UniqueConstraint(fields=('scope_type', 'scope_id', 'slug'), name='ipam_vlangroup_unique_scope_slug'), + constraint=models.UniqueConstraint( + fields=('scope_type', 'scope_id', 'slug'), name='ipam_vlangroup_unique_scope_slug' + ), ), migrations.AddField( model_name='aggregate', @@ -365,15 +446,32 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('name', models.CharField(max_length=100, unique=True)), ('slug', models.SlugField(max_length=100, unique=True)), ('start', ipam.fields.ASNField()), ('end', ipam.fields.ASNField()), - ('rir', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='asn_ranges', to='ipam.rir')), + ( + 'rir', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='asn_ranges', to='ipam.rir' + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='asn_ranges', to='tenancy.tenant')), + ( + 'tenant', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='asn_ranges', + to='tenancy.tenant', + ), + ), ], options={ 'verbose_name': 'ASN range', @@ -388,6 +486,11 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='ipaddress', - index=models.Index(django.db.models.functions.comparison.Cast(ipam.lookups.Host('address'), output_field=ipam.fields.IPAddressField()), name='ipam_ipaddress_host'), + index=models.Index( + django.db.models.functions.comparison.Cast( + ipam.lookups.Host('address'), output_field=ipam.fields.IPAddressField() + ), + name='ipam_ipaddress_host', + ), ), ] diff --git a/netbox/ipam/migrations/0068_move_l2vpn.py b/netbox/ipam/migrations/0068_move_l2vpn.py index b1a059de1..9240240bc 100644 --- a/netbox/ipam/migrations/0068_move_l2vpn.py +++ b/netbox/ipam/migrations/0068_move_l2vpn.py @@ -15,7 +15,6 @@ def update_content_types(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('ipam', '0067_ipaddress_index_host'), ] @@ -57,8 +56,5 @@ class Migration(migrations.Migration): ), ], ), - migrations.RunPython( - code=update_content_types, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_content_types, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/ipam/migrations/0069_gfk_indexes.py b/netbox/ipam/migrations/0069_gfk_indexes.py index 75c016102..d7ce48e35 100644 --- a/netbox/ipam/migrations/0069_gfk_indexes.py +++ b/netbox/ipam/migrations/0069_gfk_indexes.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('ipam', '0068_move_l2vpn'), ] @@ -16,7 +15,9 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='ipaddress', - index=models.Index(fields=['assigned_object_type', 'assigned_object_id'], name='ipam_ipaddr_assigne_890ab8_idx'), + index=models.Index( + fields=['assigned_object_type', 'assigned_object_id'], name='ipam_ipaddr_assigne_890ab8_idx' + ), ), migrations.AddIndex( model_name='vlangroup', diff --git a/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py b/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py index b01941401..133173234 100644 --- a/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py +++ b/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py @@ -12,15 +12,12 @@ def set_vid_ranges(apps, schema_editor): """ VLANGroup = apps.get_model('ipam', 'VLANGroup') for group in VLANGroup.objects.all(): - group.vid_ranges = [ - NumericRange(group.min_vid, group.max_vid, bounds='[]') - ] + group.vid_ranges = [NumericRange(group.min_vid, group.max_vid, bounds='[]')] group._total_vlan_ids = group.max_vid - group.min_vid + 1 group.save() class Migration(migrations.Migration): - dependencies = [ ('ipam', '0069_gfk_indexes'), ] @@ -32,7 +29,7 @@ class Migration(migrations.Migration): field=django.contrib.postgres.fields.ArrayField( base_field=django.contrib.postgres.fields.ranges.IntegerRangeField(), default=ipam.models.vlans.default_vid_ranges, - size=None + size=None, ), ), migrations.AddField( @@ -40,10 +37,7 @@ class Migration(migrations.Migration): name='_total_vlan_ids', field=models.PositiveBigIntegerField(default=4094), ), - migrations.RunPython( - code=set_vid_ranges, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_vid_ranges, reverse_code=migrations.RunPython.noop), migrations.RemoveField( model_name='vlangroup', name='max_vid', diff --git a/netbox/ipam/migrations/0071_prefix_scope.py b/netbox/ipam/migrations/0071_prefix_scope.py index d016bdb93..2ab54d023 100644 --- a/netbox/ipam/migrations/0071_prefix_scope.py +++ b/netbox/ipam/migrations/0071_prefix_scope.py @@ -11,13 +11,11 @@ def copy_site_assignments(apps, schema_editor): Site = apps.get_model('dcim', 'Site') Prefix.objects.filter(site__isnull=False).update( - scope_type=ContentType.objects.get_for_model(Site), - scope_id=models.F('site_id') + scope_type=ContentType.objects.get_for_model(Site), scope_id=models.F('site_id') ) class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('ipam', '0070_vlangroup_vlan_id_ranges'), @@ -39,13 +37,9 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', - to='contenttypes.contenttype' + to='contenttypes.contenttype', ), ), - # Copy over existing site assignments - migrations.RunPython( - code=copy_site_assignments, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=copy_site_assignments, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/ipam/migrations/0072_prefix_cached_relations.py b/netbox/ipam/migrations/0072_prefix_cached_relations.py index 4b438f7d5..e4a789704 100644 --- a/netbox/ipam/migrations/0072_prefix_cached_relations.py +++ b/netbox/ipam/migrations/0072_prefix_cached_relations.py @@ -19,7 +19,6 @@ def populate_denormalized_fields(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('dcim', '0193_poweroutlet_color'), ('ipam', '0071_prefix_scope'), @@ -29,12 +28,16 @@ class Migration(migrations.Migration): migrations.AddField( model_name='prefix', name='_location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location' + ), ), migrations.AddField( model_name='prefix', name='_region', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region' + ), ), migrations.AddField( model_name='prefix', @@ -44,15 +47,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='prefix', name='_site_group', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup'), + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup' + ), ), - # Populate denormalized FK values - migrations.RunPython( - code=populate_denormalized_fields, - reverse_code=migrations.RunPython.noop - ), - + migrations.RunPython(code=populate_denormalized_fields, reverse_code=migrations.RunPython.noop), # Delete the site ForeignKey migrations.RemoveField( model_name='prefix', diff --git a/netbox/ipam/migrations/0073_charfield_null_choices.py b/netbox/ipam/migrations/0073_charfield_null_choices.py index 9293728f5..cfb764b46 100644 --- a/netbox/ipam/migrations/0073_charfield_null_choices.py +++ b/netbox/ipam/migrations/0073_charfield_null_choices.py @@ -13,7 +13,6 @@ def set_null_values(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('ipam', '0072_prefix_cached_relations'), ] @@ -29,8 +28,5 @@ class Migration(migrations.Migration): name='role', field=models.CharField(blank=True, max_length=50, null=True), ), - migrations.RunPython( - code=set_null_values, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_null_values, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/ipam/migrations/0074_vlantranslationpolicy_vlantranslationrule.py b/netbox/ipam/migrations/0074_vlantranslationpolicy_vlantranslationrule.py index ca3943649..5a13f18e6 100644 --- a/netbox/ipam/migrations/0074_vlantranslationpolicy_vlantranslationrule.py +++ b/netbox/ipam/migrations/0074_vlantranslationpolicy_vlantranslationrule.py @@ -8,7 +8,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('extras', '0121_customfield_related_object_filter'), ('ipam', '0073_charfield_null_choices'), @@ -21,7 +20,10 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('comments', models.TextField(blank=True)), ('name', models.CharField(max_length=100, unique=True)), ('description', models.CharField(blank=True, max_length=200)), @@ -39,24 +41,57 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), - ('local_vid', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4094)])), - ('remote_vid', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4094)])), - ('policy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rules', to='ipam.vlantranslationpolicy')), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), + ( + 'local_vid', + models.PositiveSmallIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(4094), + ] + ), + ), + ( + 'remote_vid', + models.PositiveSmallIntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(4094), + ] + ), + ), + ( + 'policy', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='rules', + to='ipam.vlantranslationpolicy', + ), + ), ('description', models.CharField(blank=True, max_length=200)), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ 'verbose_name': 'VLAN translation rule', - 'ordering': ('policy', 'local_vid',), + 'ordering': ( + 'policy', + 'local_vid', + ), }, ), migrations.AddConstraint( model_name='vlantranslationrule', - constraint=models.UniqueConstraint(fields=('policy', 'local_vid'), name='ipam_vlantranslationrule_unique_policy_local_vid'), + constraint=models.UniqueConstraint( + fields=('policy', 'local_vid'), name='ipam_vlantranslationrule_unique_policy_local_vid' + ), ), migrations.AddConstraint( model_name='vlantranslationrule', - constraint=models.UniqueConstraint(fields=('policy', 'remote_vid'), name='ipam_vlantranslationrule_unique_policy_remote_vid'), + constraint=models.UniqueConstraint( + fields=('policy', 'remote_vid'), name='ipam_vlantranslationrule_unique_policy_remote_vid' + ), ), ] diff --git a/netbox/ipam/migrations/0075_vlan_qinq.py b/netbox/ipam/migrations/0075_vlan_qinq.py index 8a3b8a39a..1e8f86c36 100644 --- a/netbox/ipam/migrations/0075_vlan_qinq.py +++ b/netbox/ipam/migrations/0075_vlan_qinq.py @@ -3,7 +3,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('ipam', '0074_vlantranslationpolicy_vlantranslationrule'), ] @@ -17,7 +16,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='vlan', name='qinq_svlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='qinq_cvlans', to='ipam.vlan'), + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='qinq_cvlans', + to='ipam.vlan', + ), ), migrations.AddConstraint( model_name='vlan', diff --git a/netbox/ipam/migrations/0076_natural_ordering.py b/netbox/ipam/migrations/0076_natural_ordering.py index 8c7bfaea1..f6c9e5ccb 100644 --- a/netbox/ipam/migrations/0076_natural_ordering.py +++ b/netbox/ipam/migrations/0076_natural_ordering.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('ipam', '0075_vlan_qinq'), ('dcim', '0197_natural_sort_collation'), diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index dcecbcdea..e1a8d91e3 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -418,7 +418,9 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary available_ips = prefix - child_ips - netaddr.IPSet(child_ranges) # IPv6 /127's, pool, or IPv4 /31-/32 sets are fully usable - if (self.family == 6 and self.prefix.prefixlen >= 127) or self.is_pool or (self.family == 4 and self.prefix.prefixlen >= 31): + if (self.family == 6 and self.prefix.prefixlen >= 127) or self.is_pool or ( + self.family == 4 and self.prefix.prefixlen >= 31 + ): return available_ips if self.family == 4: @@ -561,10 +563,26 @@ class IPRange(ContactsMixin, PrimaryModel): }) # Check for overlapping ranges - overlapping_ranges = IPRange.objects.exclude(pk=self.pk).filter(vrf=self.vrf).filter( - Q(start_address__host__inet__gte=self.start_address.ip, start_address__host__inet__lte=self.end_address.ip) | # Starts inside - Q(end_address__host__inet__gte=self.start_address.ip, end_address__host__inet__lte=self.end_address.ip) | # Ends inside - Q(start_address__host__inet__lte=self.start_address.ip, end_address__host__inet__gte=self.end_address.ip) # Starts & ends outside + overlapping_ranges = ( + IPRange.objects.exclude(pk=self.pk) + .filter(vrf=self.vrf) + .filter( + # Starts inside + Q( + start_address__host__inet__gte=self.start_address.ip, + start_address__host__inet__lte=self.end_address.ip, + ) | + # Ends inside + Q( + end_address__host__inet__gte=self.start_address.ip, + end_address__host__inet__lte=self.end_address.ip, + ) | + # Starts & ends outside + Q( + start_address__host__inet__lte=self.start_address.ip, + end_address__host__inet__gte=self.end_address.ip, + ) + ) ) if overlapping_ranges.exists(): raise ValidationError( @@ -866,10 +884,12 @@ class IPAddress(ContactsMixin, PrimaryModel): # can't use is_primary_ip as self.assigned_object might be changed is_primary = False - if self.family == 4 and hasattr(original_parent, 'primary_ip4') and original_parent.primary_ip4_id == self.pk: - is_primary = True - if self.family == 6 and hasattr(original_parent, 'primary_ip6') and original_parent.primary_ip6_id == self.pk: - is_primary = True + if self.family == 4 and hasattr(original_parent, 'primary_ip4'): + if original_parent.primary_ip4_id == self.pk: + is_primary = True + if self.family == 6 and hasattr(original_parent, 'primary_ip6'): + if original_parent.primary_ip6_id == self.pk: + is_primary = True if is_primary and (parent != original_parent): raise ValidationError( diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index fa31fd608..dfa814619 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -96,16 +96,32 @@ class VLANGroup(OrganizationalModel): raise ValidationError(_("Cannot set scope_id without scope_type.")) # Validate VID ranges - if self.vid_ranges and check_ranges_overlap(self.vid_ranges): - raise ValidationError({'vid_ranges': _("Ranges cannot overlap.")}) for vid_range in self.vid_ranges: - if vid_range.lower > vid_range.upper: + lower_vid = vid_range.lower if vid_range.lower_inc else vid_range.lower + 1 + upper_vid = vid_range.upper if vid_range.upper_inc else vid_range.upper - 1 + if lower_vid < VLAN_VID_MIN: + raise ValidationError({ + 'vid_ranges': _("Starting VLAN ID in range ({value}) cannot be less than {minimum}").format( + value=lower_vid, minimum=VLAN_VID_MIN + ) + }) + if upper_vid > VLAN_VID_MAX: + raise ValidationError({ + 'vid_ranges': _("Ending VLAN ID in range ({value}) cannot exceed {maximum}").format( + value=upper_vid, maximum=VLAN_VID_MAX + ) + }) + if lower_vid > upper_vid: raise ValidationError({ 'vid_ranges': _( - "Maximum child VID must be greater than or equal to minimum child VID ({value})" - ).format(value=vid_range) + "Ending VLAN ID in range must be greater than or equal to the starting VLAN ID ({range})" + ).format(range=f'{lower_vid}-{upper_vid}') }) + # Check for overlapping VID ranges + if self.vid_ranges and check_ranges_overlap(self.vid_ranges): + raise ValidationError({'vid_ranges': _("Ranges cannot overlap.")}) + def save(self, *args, **kwargs): self._total_vlan_ids = 0 for vid_range in self.vid_ranges: diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 399641422..dbbeb3454 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -6,6 +6,7 @@ from django_tables2.utils import Accessor from ipam.models import * from netbox.tables import NetBoxTable, columns from tenancy.tables import TenancyColumnsMixin, TenantColumn +from .template_code import * __all__ = ( 'AggregateTable', @@ -20,61 +21,6 @@ __all__ = ( AVAILABLE_LABEL = mark_safe('Available') -AGGREGATE_COPY_BUTTON = """ -{% copy_content record.pk prefix="aggregate_" %} -""" - -PREFIX_LINK = """ -{% if record.pk %} - {{ record.prefix }} -{% else %} - {{ record.prefix }} -{% endif %} -""" - -PREFIX_COPY_BUTTON = """ -{% copy_content record.pk prefix="prefix_" %} -""" - -PREFIX_LINK_WITH_DEPTH = """ -{% load helpers %} -{% if record.depth %} -
    - {% for i in record.depth|as_range %} - - {% endfor %} -
    -{% endif %} -""" + PREFIX_LINK - -IPADDRESS_LINK = """ -{% if record.pk %} - {{ record.address }} -{% elif perms.ipam.add_ipaddress %} - {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available -{% else %} - {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available -{% endif %} -""" - -IPADDRESS_COPY_BUTTON = """ -{% copy_content record.pk prefix="ipaddress_" %} -""" - -IPADDRESS_ASSIGN_LINK = """ -{{ record }} -""" - -VRF_LINK = """ -{% if value %} - {{ record.vrf }} -{% elif object.vrf %} - {{ object.vrf }} -{% else %} - Global -{% endif %} -""" - # # RIRs diff --git a/netbox/ipam/tables/template_code.py b/netbox/ipam/tables/template_code.py new file mode 100644 index 000000000..fb969345e --- /dev/null +++ b/netbox/ipam/tables/template_code.py @@ -0,0 +1,88 @@ +AGGREGATE_COPY_BUTTON = """ +{% copy_content record.pk prefix="aggregate_" %} +""" + +PREFIX_LINK = """ +{% if record.pk %} + {{ record.prefix }} +{% else %} + {{ record.prefix }} +{% endif %} +""" + +PREFIX_COPY_BUTTON = """ +{% copy_content record.pk prefix="prefix_" %} +""" + +PREFIX_LINK_WITH_DEPTH = """ +{% load helpers %} +{% if record.depth %} +
    + {% for i in record.depth|as_range %} + + {% endfor %} +
    +{% endif %} +""" + PREFIX_LINK + +IPADDRESS_LINK = """ +{% if record.pk %} + {{ record.address }} +{% elif perms.ipam.add_ipaddress %} + {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available +{% else %} + {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available +{% endif %} +""" + +IPADDRESS_COPY_BUTTON = """ +{% copy_content record.pk prefix="ipaddress_" %} +""" + +IPADDRESS_ASSIGN_LINK = """ +{{ record }} +""" + +VRF_LINK = """ +{% if value %} + {{ record.vrf }} +{% elif object.vrf %} + {{ object.vrf }} +{% else %} + Global +{% endif %} +""" + +VLAN_LINK = """ +{% if record.pk %} + {{ record.vid }} +{% elif perms.ipam.add_vlan %} + {{ record.available }} VLAN{{ record.available|pluralize }} available +{% else %} + {{ record.available }} VLAN{{ record.available|pluralize }} available +{% endif %} +""" + +VLAN_PREFIXES = """ +{% for prefix in value.all %} + {{ prefix }}{% if not forloop.last %}
    {% endif %} +{% endfor %} +""" + +VLANGROUP_BUTTONS = """ +{% with next_vid=record.get_next_available_vid %} + {% if next_vid and perms.ipam.add_vlan %} + + + + {% endif %} +{% endwith %} +""" + +VLAN_MEMBER_TAGGED = """ +{% if record.untagged_vlan_id == object.pk %} + +{% else %} + +{% endif %} +""" diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index d34ff5f45..e3d7c7e63 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -8,6 +8,7 @@ from ipam.models import * from netbox.tables import NetBoxTable, columns from tenancy.tables import TenancyColumnsMixin, TenantColumn from virtualization.models import VMInterface +from .template_code import * __all__ = ( 'InterfaceVLANTable', @@ -22,40 +23,6 @@ __all__ = ( AVAILABLE_LABEL = mark_safe('Available') -VLAN_LINK = """ -{% if record.pk %} - {{ record.vid }} -{% elif perms.ipam.add_vlan %} - {{ record.available }} VLAN{{ record.available|pluralize }} available -{% else %} - {{ record.available }} VLAN{{ record.available|pluralize }} available -{% endif %} -""" - -VLAN_PREFIXES = """ -{% for prefix in value.all %} - {{ prefix }}{% if not forloop.last %}
    {% endif %} -{% endfor %} -""" - -VLANGROUP_BUTTONS = """ -{% with next_vid=record.get_next_available_vid %} - {% if next_vid and perms.ipam.add_vlan %} - - - - {% endif %} -{% endwith %} -""" - -VLAN_MEMBER_TAGGED = """ -{% if record.untagged_vlan_id == object.pk %} - -{% else %} - -{% endif %} -""" - # # VLAN groups diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 4e8456e5a..cbcb2e7c8 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -732,10 +732,19 @@ class FHRPGroupTest(APIViewTestCases.APIViewTestCase): @classmethod def setUpTestData(cls): - fhrp_groups = ( - FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP2, group_id=10, auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, auth_key='foobar123'), - FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP3, group_id=20, auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5, auth_key='foobar123'), + FHRPGroup( + protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP2, + group_id=10, + auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, + auth_key='foobar123', + ), + FHRPGroup( + protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP3, + group_id=20, + auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5, + auth_key='foobar123', + ), FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP, group_id=30), ) FHRPGroup.objects.bulk_create(fhrp_groups) diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index 28e8cda1e..5455beb9c 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -496,8 +496,12 @@ class AggregateTestCase(TestCase, ChangeLoggedFilterSetTests): Tenant.objects.bulk_create(tenants) aggregates = ( - Aggregate(prefix='10.1.0.0/16', rir=rirs[0], tenant=tenants[0], date_added='2020-01-01', description='foobar1'), - Aggregate(prefix='10.2.0.0/16', rir=rirs[0], tenant=tenants[1], date_added='2020-01-02', description='foobar2'), + Aggregate( + prefix='10.1.0.0/16', rir=rirs[0], tenant=tenants[0], date_added='2020-01-01', description='foobar1' + ), + Aggregate( + prefix='10.2.0.0/16', rir=rirs[0], tenant=tenants[1], date_added='2020-01-02', description='foobar2' + ), Aggregate(prefix='10.3.0.0/16', rir=rirs[1], tenant=tenants[2], date_added='2020-01-03'), Aggregate(prefix='2001:db8:1::/48', rir=rirs[1], tenant=tenants[0], date_added='2020-01-04'), Aggregate(prefix='2001:db8:2::/48', rir=rirs[2], tenant=tenants[1], date_added='2020-01-05'), @@ -656,14 +660,80 @@ class PrefixTestCase(TestCase, ChangeLoggedFilterSetTests): Tenant.objects.bulk_create(tenants) prefixes = ( - Prefix(prefix='10.0.0.0/24', tenant=None, scope=None, vrf=None, vlan=None, role=None, is_pool=True, mark_utilized=True, description='foobar1'), - Prefix(prefix='10.0.1.0/24', tenant=tenants[0], scope=sites[0], vrf=vrfs[0], vlan=vlans[0], role=roles[0], description='foobar2'), - Prefix(prefix='10.0.2.0/24', tenant=tenants[1], scope=sites[1], vrf=vrfs[1], vlan=vlans[1], role=roles[1], status=PrefixStatusChoices.STATUS_DEPRECATED), - Prefix(prefix='10.0.3.0/24', tenant=tenants[2], scope=sites[2], vrf=vrfs[2], vlan=vlans[2], role=roles[2], status=PrefixStatusChoices.STATUS_RESERVED), - Prefix(prefix='2001:db8::/64', tenant=None, scope=None, vrf=None, vlan=None, role=None, is_pool=True, mark_utilized=True), - Prefix(prefix='2001:db8:0:1::/64', tenant=tenants[0], scope=sites[0], vrf=vrfs[0], vlan=vlans[0], role=roles[0]), - Prefix(prefix='2001:db8:0:2::/64', tenant=tenants[1], scope=sites[1], vrf=vrfs[1], vlan=vlans[1], role=roles[1], status=PrefixStatusChoices.STATUS_DEPRECATED), - Prefix(prefix='2001:db8:0:3::/64', tenant=tenants[2], scope=sites[2], vrf=vrfs[2], vlan=vlans[2], role=roles[2], status=PrefixStatusChoices.STATUS_RESERVED), + Prefix( + prefix='10.0.0.0/24', + tenant=None, + scope=None, + vrf=None, + vlan=None, + role=None, + is_pool=True, + mark_utilized=True, + description='foobar1', + ), + Prefix( + prefix='10.0.1.0/24', + tenant=tenants[0], + scope=sites[0], + vrf=vrfs[0], + vlan=vlans[0], + role=roles[0], + description='foobar2', + ), + Prefix( + prefix='10.0.2.0/24', + tenant=tenants[1], + scope=sites[1], + vrf=vrfs[1], + vlan=vlans[1], + role=roles[1], + status=PrefixStatusChoices.STATUS_DEPRECATED, + ), + Prefix( + prefix='10.0.3.0/24', + tenant=tenants[2], + scope=sites[2], + vrf=vrfs[2], + vlan=vlans[2], + role=roles[2], + status=PrefixStatusChoices.STATUS_RESERVED, + ), + Prefix( + prefix='2001:db8::/64', + tenant=None, + scope=None, + vrf=None, + vlan=None, + role=None, + is_pool=True, + mark_utilized=True, + ), + Prefix( + prefix='2001:db8:0:1::/64', + tenant=tenants[0], + scope=sites[0], + vrf=vrfs[0], + vlan=vlans[0], + role=roles[0] + ), + Prefix( + prefix='2001:db8:0:2::/64', + tenant=tenants[1], + scope=sites[1], + vrf=vrfs[1], + vlan=vlans[1], + role=roles[1], + status=PrefixStatusChoices.STATUS_DEPRECATED, + ), + Prefix( + prefix='2001:db8:0:3::/64', + tenant=tenants[2], + scope=sites[2], + vrf=vrfs[2], + vlan=vlans[2], + role=roles[2], + status=PrefixStatusChoices.STATUS_RESERVED, + ), Prefix(prefix='10.0.0.0/16'), Prefix(prefix='2001:db8::/32'), ) @@ -1365,7 +1435,10 @@ class FHRPGroupTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) def test_auth_type(self): - params = {'auth_type': [FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5]} + params = {'auth_type': [ + FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, + FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5, + ]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) def test_auth_key(self): @@ -1653,9 +1726,15 @@ class VLANTestCase(TestCase, ChangeLoggedFilterSetTests): device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1') role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') devices = ( - Device(name='Device 1', site=sites[0], location=locations[0], rack=racks[0], device_type=device_type, role=role), - Device(name='Device 2', site=sites[1], location=locations[1], rack=racks[1], device_type=device_type, role=role), - Device(name='Device 3', site=sites[2], location=locations[2], rack=racks[2], device_type=device_type, role=role), + Device( + name='Device 1', site=sites[0], location=locations[0], rack=racks[0], device_type=device_type, role=role + ), + Device( + name='Device 2', site=sites[1], location=locations[1], rack=racks[1], device_type=device_type, role=role + ), + Device( + name='Device 3', site=sites[2], location=locations[2], rack=racks[2], device_type=device_type, role=role + ), ) Device.objects.bulk_create(devices) @@ -1773,20 +1852,64 @@ class VLANTestCase(TestCase, ChangeLoggedFilterSetTests): VLAN(vid=19, name='Cluster 1', group=groups[18]), VLAN(vid=20, name='Cluster 2', group=groups[19]), VLAN(vid=21, name='Cluster 3', group=groups[20]), - - VLAN(vid=101, name='VLAN 101', site=sites[3], group=groups[21], role=roles[0], tenant=tenants[0], status=VLANStatusChoices.STATUS_ACTIVE), - VLAN(vid=102, name='VLAN 102', site=sites[3], group=groups[21], role=roles[0], tenant=tenants[0], status=VLANStatusChoices.STATUS_ACTIVE), - VLAN(vid=201, name='VLAN 201', site=sites[4], group=groups[22], role=roles[1], tenant=tenants[1], status=VLANStatusChoices.STATUS_DEPRECATED), - VLAN(vid=202, name='VLAN 202', site=sites[4], group=groups[22], role=roles[1], tenant=tenants[1], status=VLANStatusChoices.STATUS_DEPRECATED), - VLAN(vid=301, name='VLAN 301', site=sites[5], group=groups[23], role=roles[2], tenant=tenants[2], status=VLANStatusChoices.STATUS_RESERVED), - VLAN(vid=302, name='VLAN 302', site=sites[5], group=groups[23], role=roles[2], tenant=tenants[2], status=VLANStatusChoices.STATUS_RESERVED), - + VLAN( + vid=101, + name='VLAN 101', + site=sites[3], + group=groups[21], + role=roles[0], + tenant=tenants[0], + status=VLANStatusChoices.STATUS_ACTIVE, + ), + VLAN( + vid=102, + name='VLAN 102', + site=sites[3], + group=groups[21], + role=roles[0], + tenant=tenants[0], + status=VLANStatusChoices.STATUS_ACTIVE, + ), + VLAN( + vid=201, + name='VLAN 201', + site=sites[4], + group=groups[22], + role=roles[1], + tenant=tenants[1], + status=VLANStatusChoices.STATUS_DEPRECATED, + ), + VLAN( + vid=202, + name='VLAN 202', + site=sites[4], + group=groups[22], + role=roles[1], + tenant=tenants[1], + status=VLANStatusChoices.STATUS_DEPRECATED, + ), + VLAN( + vid=301, + name='VLAN 301', + site=sites[5], + group=groups[23], + role=roles[2], + tenant=tenants[2], + status=VLANStatusChoices.STATUS_RESERVED, + ), + VLAN( + vid=302, + name='VLAN 302', + site=sites[5], + group=groups[23], + role=roles[2], + tenant=tenants[2], + status=VLANStatusChoices.STATUS_RESERVED, + ), # Create one globally available VLAN on a VLAN group VLAN(vid=500, name='VLAN Group 1', group=groups[24]), - # Create one globally available VLAN VLAN(vid=1000, name='Global VLAN'), - # Create some Q-in-Q service VLANs VLAN(vid=2001, name='SVLAN 1', site=sites[6], qinq_role=VLANQinQRoleChoices.ROLE_SERVICE), VLAN(vid=2002, name='SVLAN 2', site=sites[6], qinq_role=VLANQinQRoleChoices.ROLE_SERVICE), @@ -1795,11 +1918,31 @@ class VLANTestCase(TestCase, ChangeLoggedFilterSetTests): VLAN.objects.bulk_create(vlans) # Create Q-in-Q customer VLANs - VLAN.objects.bulk_create([ - VLAN(vid=3001, name='CVLAN 1', site=sites[6], qinq_svlan=vlans[29], qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER), - VLAN(vid=3002, name='CVLAN 2', site=sites[6], qinq_svlan=vlans[30], qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER), - VLAN(vid=3003, name='CVLAN 3', site=sites[6], qinq_svlan=vlans[31], qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER), - ]) + VLAN.objects.bulk_create( + [ + VLAN( + vid=3001, + name='CVLAN 1', + site=sites[6], + qinq_svlan=vlans[29], + qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER, + ), + VLAN( + vid=3002, + name='CVLAN 2', + site=sites[6], + qinq_svlan=vlans[30], + qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER, + ), + VLAN( + vid=3003, + name='CVLAN 3', + site=sites[6], + qinq_svlan=vlans[31], + qinq_role=VLANQinQRoleChoices.ROLE_CUSTOMER, + ), + ] + ) # Assign VLANs to device interfaces interfaces[0].untagged_vlan = vlans[0] @@ -2125,12 +2268,39 @@ class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests): VirtualMachine.objects.bulk_create(virtual_machines) services = ( - Service(device=devices[0], name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1001], description='foobar1'), - Service(device=devices[1], name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1002], description='foobar2'), + Service( + device=devices[0], + name='Service 1', + protocol=ServiceProtocolChoices.PROTOCOL_TCP, + ports=[1001], + description='foobar1', + ), + Service( + device=devices[1], + name='Service 2', + protocol=ServiceProtocolChoices.PROTOCOL_TCP, + ports=[1002], + description='foobar2', + ), Service(device=devices[2], name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_UDP, ports=[1003]), - Service(virtual_machine=virtual_machines[0], name='Service 4', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[2001]), - Service(virtual_machine=virtual_machines[1], name='Service 5', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[2002]), - Service(virtual_machine=virtual_machines[2], name='Service 6', protocol=ServiceProtocolChoices.PROTOCOL_UDP, ports=[2003]), + Service( + virtual_machine=virtual_machines[0], + name='Service 4', + protocol=ServiceProtocolChoices.PROTOCOL_TCP, + ports=[2001], + ), + Service( + virtual_machine=virtual_machines[1], + name='Service 5', + protocol=ServiceProtocolChoices.PROTOCOL_TCP, + ports=[2002], + ), + Service( + virtual_machine=virtual_machines[2], + name='Service 6', + protocol=ServiceProtocolChoices.PROTOCOL_UDP, + ports=[2003], + ), ) Service.objects.bulk_create(services) services[0].ipaddresses.add(ip_addresses[0]) diff --git a/netbox/ipam/tests/test_models.py b/netbox/ipam/tests/test_models.py index 917b50f33..62eb74123 100644 --- a/netbox/ipam/tests/test_models.py +++ b/netbox/ipam/tests/test_models.py @@ -39,29 +39,50 @@ class TestAggregate(TestCase): class TestIPRange(TestCase): def test_overlapping_range(self): - iprange_192_168 = IPRange.objects.create(start_address=IPNetwork('192.168.0.1/22'), end_address=IPNetwork('192.168.0.49/22')) + iprange_192_168 = IPRange.objects.create( + start_address=IPNetwork('192.168.0.1/22'), end_address=IPNetwork('192.168.0.49/22') + ) iprange_192_168.clean() - iprange_3_1_99 = IPRange.objects.create(start_address=IPNetwork('1.2.3.1/24'), end_address=IPNetwork('1.2.3.99/24')) + iprange_3_1_99 = IPRange.objects.create( + start_address=IPNetwork('1.2.3.1/24'), end_address=IPNetwork('1.2.3.99/24') + ) iprange_3_1_99.clean() - iprange_3_100_199 = IPRange.objects.create(start_address=IPNetwork('1.2.3.100/24'), end_address=IPNetwork('1.2.3.199/24')) + iprange_3_100_199 = IPRange.objects.create( + start_address=IPNetwork('1.2.3.100/24'), end_address=IPNetwork('1.2.3.199/24') + ) iprange_3_100_199.clean() - iprange_3_200_255 = IPRange.objects.create(start_address=IPNetwork('1.2.3.200/24'), end_address=IPNetwork('1.2.3.255/24')) + iprange_3_200_255 = IPRange.objects.create( + start_address=IPNetwork('1.2.3.200/24'), end_address=IPNetwork('1.2.3.255/24') + ) iprange_3_200_255.clean() - iprange_4_1_99 = IPRange.objects.create(start_address=IPNetwork('1.2.4.1/24'), end_address=IPNetwork('1.2.4.99/24')) + iprange_4_1_99 = IPRange.objects.create( + start_address=IPNetwork('1.2.4.1/24'), end_address=IPNetwork('1.2.4.99/24') + ) iprange_4_1_99.clean() - iprange_4_200 = IPRange.objects.create(start_address=IPNetwork('1.2.4.200/24'), end_address=IPNetwork('1.2.4.255/24')) + iprange_4_200 = IPRange.objects.create( + start_address=IPNetwork('1.2.4.200/24'), end_address=IPNetwork('1.2.4.255/24') + ) iprange_4_200.clean() + # Overlapping range entirely within existing with self.assertRaises(ValidationError): - iprange_3_123_124 = IPRange.objects.create(start_address=IPNetwork('1.2.3.123/26'), end_address=IPNetwork('1.2.3.124/26')) + iprange_3_123_124 = IPRange.objects.create( + start_address=IPNetwork('1.2.3.123/26'), end_address=IPNetwork('1.2.3.124/26') + ) iprange_3_123_124.clean() + # Overlapping range starting within existing with self.assertRaises(ValidationError): - iprange_4_98_101 = IPRange.objects.create(start_address=IPNetwork('1.2.4.98/24'), end_address=IPNetwork('1.2.4.101/24')) + iprange_4_98_101 = IPRange.objects.create( + start_address=IPNetwork('1.2.4.98/24'), end_address=IPNetwork('1.2.4.101/24') + ) iprange_4_98_101.clean() + # Overlapping range ending within existing with self.assertRaises(ValidationError): - iprange_4_198_201 = IPRange.objects.create(start_address=IPNetwork('1.2.4.198/24'), end_address=IPNetwork('1.2.4.201/24')) + iprange_4_198_201 = IPRange.objects.create( + start_address=IPNetwork('1.2.4.198/24'), end_address=IPNetwork('1.2.4.201/24') + ) iprange_4_198_201.clean() @@ -105,13 +126,30 @@ class TestPrefix(TestCase): def test_get_child_ranges(self): prefix = Prefix(prefix='192.168.0.16/28') prefix.save() - ranges = IPRange.objects.bulk_create(( - IPRange(start_address=IPNetwork('192.168.0.1/24'), end_address=IPNetwork('192.168.0.10/24'), size=10), # No overlap - IPRange(start_address=IPNetwork('192.168.0.11/24'), end_address=IPNetwork('192.168.0.17/24'), size=7), # Partial overlap - IPRange(start_address=IPNetwork('192.168.0.18/24'), end_address=IPNetwork('192.168.0.23/24'), size=6), # Full overlap - IPRange(start_address=IPNetwork('192.168.0.24/24'), end_address=IPNetwork('192.168.0.30/24'), size=7), # Full overlap - IPRange(start_address=IPNetwork('192.168.0.31/24'), end_address=IPNetwork('192.168.0.40/24'), size=10), # Partial overlap - )) + ranges = IPRange.objects.bulk_create( + ( + # No overlap + IPRange( + start_address=IPNetwork('192.168.0.1/24'), end_address=IPNetwork('192.168.0.10/24'), size=10 + ), + # Partial overlap + IPRange( + start_address=IPNetwork('192.168.0.11/24'), end_address=IPNetwork('192.168.0.17/24'), size=7 + ), + # Full overlap + IPRange( + start_address=IPNetwork('192.168.0.18/24'), end_address=IPNetwork('192.168.0.23/24'), size=6 + ), + # Full overlap + IPRange( + start_address=IPNetwork('192.168.0.24/24'), end_address=IPNetwork('192.168.0.30/24'), size=7 + ), + # Partial overlap + IPRange( + start_address=IPNetwork('192.168.0.31/24'), end_address=IPNetwork('192.168.0.40/24'), size=10 + ), + ) + ) child_ranges = prefix.get_child_ranges() diff --git a/netbox/ipam/tests/test_ordering.py b/netbox/ipam/tests/test_ordering.py index fea6b55e2..2f7a5342d 100644 --- a/netbox/ipam/tests/test_ordering.py +++ b/netbox/ipam/tests/test_ordering.py @@ -92,8 +92,8 @@ class PrefixOrderingTestCase(OrderingTestBase): def test_prefix_complex_ordering(self): """ - This function tests a complex ordering of interwoven prefixes and vrfs. This is the current expected ordering of VRFs - This includes the testing of the Container status. + This function tests a complex ordering of interwoven prefixes and vrfs. This is the current expected ordering + of VRFs. This includes the testing of the Container status. The proper ordering, to get proper containerization should be: None:10.0.0.0/8 @@ -125,7 +125,6 @@ class PrefixOrderingTestCase(OrderingTestBase): class IPAddressOrderingTestCase(OrderingTestBase): - def test_address_vrf_ordering(self): """ This function tests ordering with the inclusion of vrfs @@ -147,24 +146,54 @@ class IPAddressOrderingTestCase(OrderingTestBase): IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf1, address=netaddr.IPNetwork('10.2.2.1/24')), IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf1, address=netaddr.IPNetwork('10.2.3.1/24')), IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf1, address=netaddr.IPNetwork('10.2.4.1/24')), - - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.0.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.1.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.2.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.3.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.4.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.0.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.1.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.2.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.3.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.4.1/24')), - - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.0.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.1.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.2.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.3.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.4.1/24')), - IPAddress(status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.5.1/24')), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.0.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.1.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.2.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.3.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.16.4.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.0.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.1.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.2.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.3.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=vrf2, address=netaddr.IPNetwork('172.17.4.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.0.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.1.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.2.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.3.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.4.1/24') + ), + IPAddress( + status=IPAddressStatusChoices.STATUS_ACTIVE, vrf=None, address=netaddr.IPNetwork('192.168.5.1/24') + ), ) IPAddress.objects.bulk_create(addresses) diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index c45777f08..d26a82414 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -707,11 +707,23 @@ class FHRPGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase): @classmethod def setUpTestData(cls): - fhrp_groups = ( - FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP2, group_id=10, auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, auth_key='foobar123'), - FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP3, group_id=20, auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5, auth_key='foobar123'), - FHRPGroup(protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP, group_id=30), + FHRPGroup( + protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP2, + group_id=10, + auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT, + auth_key='foobar123', + ), + FHRPGroup( + protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP3, + group_id=20, + auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5, + auth_key='foobar123', + ), + FHRPGroup( + protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP, + group_id=30 + ), ) FHRPGroup.objects.bulk_create(fhrp_groups) diff --git a/netbox/ipam/urls.py b/netbox/ipam/urls.py index d40f9c5dc..c55e874a1 100644 --- a/netbox/ipam/urls.py +++ b/netbox/ipam/urls.py @@ -1,150 +1,62 @@ from django.urls import include, path from utilities.urls import get_model_urls -from . import views +from . import views # noqa F401 app_name = 'ipam' urlpatterns = [ - # ASN ranges - path('asn-ranges/', views.ASNRangeListView.as_view(), name='asnrange_list'), - path('asn-ranges/add/', views.ASNRangeEditView.as_view(), name='asnrange_add'), - path('asn-ranges/import/', views.ASNRangeBulkImportView.as_view(), name='asnrange_import'), - path('asn-ranges/edit/', views.ASNRangeBulkEditView.as_view(), name='asnrange_bulk_edit'), - path('asn-ranges/delete/', views.ASNRangeBulkDeleteView.as_view(), name='asnrange_bulk_delete'), + path('asn-ranges/', include(get_model_urls('ipam', 'asnrange', detail=False))), path('asn-ranges//', include(get_model_urls('ipam', 'asnrange'))), - # ASNs - path('asns/', views.ASNListView.as_view(), name='asn_list'), - path('asns/add/', views.ASNEditView.as_view(), name='asn_add'), - path('asns/import/', views.ASNBulkImportView.as_view(), name='asn_import'), - path('asns/edit/', views.ASNBulkEditView.as_view(), name='asn_bulk_edit'), - path('asns/delete/', views.ASNBulkDeleteView.as_view(), name='asn_bulk_delete'), + path('asns/', include(get_model_urls('ipam', 'asn', detail=False))), path('asns//', include(get_model_urls('ipam', 'asn'))), - # VRFs - path('vrfs/', views.VRFListView.as_view(), name='vrf_list'), - path('vrfs/add/', views.VRFEditView.as_view(), name='vrf_add'), - path('vrfs/import/', views.VRFBulkImportView.as_view(), name='vrf_import'), - path('vrfs/edit/', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'), - path('vrfs/delete/', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'), + path('vrfs/', include(get_model_urls('ipam', 'vrf', detail=False))), path('vrfs//', include(get_model_urls('ipam', 'vrf'))), - # Route targets - path('route-targets/', views.RouteTargetListView.as_view(), name='routetarget_list'), - path('route-targets/add/', views.RouteTargetEditView.as_view(), name='routetarget_add'), - path('route-targets/import/', views.RouteTargetBulkImportView.as_view(), name='routetarget_import'), - path('route-targets/edit/', views.RouteTargetBulkEditView.as_view(), name='routetarget_bulk_edit'), - path('route-targets/delete/', views.RouteTargetBulkDeleteView.as_view(), name='routetarget_bulk_delete'), + path('route-targets/', include(get_model_urls('ipam', 'routetarget', detail=False))), path('route-targets//', include(get_model_urls('ipam', 'routetarget'))), - # RIRs - path('rirs/', views.RIRListView.as_view(), name='rir_list'), - path('rirs/add/', views.RIREditView.as_view(), name='rir_add'), - path('rirs/import/', views.RIRBulkImportView.as_view(), name='rir_import'), - path('rirs/edit/', views.RIRBulkEditView.as_view(), name='rir_bulk_edit'), - path('rirs/delete/', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'), + path('rirs/', include(get_model_urls('ipam', 'rir', detail=False))), path('rirs//', include(get_model_urls('ipam', 'rir'))), - # Aggregates - path('aggregates/', views.AggregateListView.as_view(), name='aggregate_list'), - path('aggregates/add/', views.AggregateEditView.as_view(), name='aggregate_add'), - path('aggregates/import/', views.AggregateBulkImportView.as_view(), name='aggregate_import'), - path('aggregates/edit/', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'), - path('aggregates/delete/', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'), + path('aggregates/', include(get_model_urls('ipam', 'aggregate', detail=False))), path('aggregates//', include(get_model_urls('ipam', 'aggregate'))), - # Roles - path('roles/', views.RoleListView.as_view(), name='role_list'), - path('roles/add/', views.RoleEditView.as_view(), name='role_add'), - path('roles/import/', views.RoleBulkImportView.as_view(), name='role_import'), - path('roles/edit/', views.RoleBulkEditView.as_view(), name='role_bulk_edit'), - path('roles/delete/', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'), + path('roles/', include(get_model_urls('ipam', 'role', detail=False))), path('roles//', include(get_model_urls('ipam', 'role'))), - # Prefixes - path('prefixes/', views.PrefixListView.as_view(), name='prefix_list'), - path('prefixes/add/', views.PrefixEditView.as_view(), name='prefix_add'), - path('prefixes/import/', views.PrefixBulkImportView.as_view(), name='prefix_import'), - path('prefixes/edit/', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), - path('prefixes/delete/', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), + path('prefixes/', include(get_model_urls('ipam', 'prefix', detail=False))), path('prefixes//', include(get_model_urls('ipam', 'prefix'))), - # IP ranges - path('ip-ranges/', views.IPRangeListView.as_view(), name='iprange_list'), - path('ip-ranges/add/', views.IPRangeEditView.as_view(), name='iprange_add'), - path('ip-ranges/import/', views.IPRangeBulkImportView.as_view(), name='iprange_import'), - path('ip-ranges/edit/', views.IPRangeBulkEditView.as_view(), name='iprange_bulk_edit'), - path('ip-ranges/delete/', views.IPRangeBulkDeleteView.as_view(), name='iprange_bulk_delete'), + path('ip-ranges/', include(get_model_urls('ipam', 'iprange', detail=False))), path('ip-ranges//', include(get_model_urls('ipam', 'iprange'))), - # IP addresses - path('ip-addresses/', views.IPAddressListView.as_view(), name='ipaddress_list'), - path('ip-addresses/add/', views.IPAddressEditView.as_view(), name='ipaddress_add'), - path('ip-addresses/bulk-add/', views.IPAddressBulkCreateView.as_view(), name='ipaddress_bulk_add'), - path('ip-addresses/import/', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'), - path('ip-addresses/edit/', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'), - path('ip-addresses/delete/', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'), - path('ip-addresses/assign/', views.IPAddressAssignView.as_view(), name='ipaddress_assign'), + path('ip-addresses/', include(get_model_urls('ipam', 'ipaddress', detail=False))), path('ip-addresses//', include(get_model_urls('ipam', 'ipaddress'))), - # FHRP groups - path('fhrp-groups/', views.FHRPGroupListView.as_view(), name='fhrpgroup_list'), - path('fhrp-groups/add/', views.FHRPGroupEditView.as_view(), name='fhrpgroup_add'), - path('fhrp-groups/import/', views.FHRPGroupBulkImportView.as_view(), name='fhrpgroup_import'), - path('fhrp-groups/edit/', views.FHRPGroupBulkEditView.as_view(), name='fhrpgroup_bulk_edit'), - path('fhrp-groups/delete/', views.FHRPGroupBulkDeleteView.as_view(), name='fhrpgroup_bulk_delete'), + path('fhrp-groups/', include(get_model_urls('ipam', 'fhrpgroup', detail=False))), path('fhrp-groups//', include(get_model_urls('ipam', 'fhrpgroup'))), - # FHRP group assignments - path('fhrp-group-assignments/add/', views.FHRPGroupAssignmentEditView.as_view(), name='fhrpgroupassignment_add'), + path('fhrp-group-assignments/', include(get_model_urls('ipam', 'fhrpgroupassignment', detail=False))), path('fhrp-group-assignments//', include(get_model_urls('ipam', 'fhrpgroupassignment'))), - # VLAN groups - path('vlan-groups/', views.VLANGroupListView.as_view(), name='vlangroup_list'), - path('vlan-groups/add/', views.VLANGroupEditView.as_view(), name='vlangroup_add'), - path('vlan-groups/import/', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'), - path('vlan-groups/edit/', views.VLANGroupBulkEditView.as_view(), name='vlangroup_bulk_edit'), - path('vlan-groups/delete/', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'), + path('vlan-groups/', include(get_model_urls('ipam', 'vlangroup', detail=False))), path('vlan-groups//', include(get_model_urls('ipam', 'vlangroup'))), - # VLANs - path('vlans/', views.VLANListView.as_view(), name='vlan_list'), - path('vlans/add/', views.VLANEditView.as_view(), name='vlan_add'), - path('vlans/import/', views.VLANBulkImportView.as_view(), name='vlan_import'), - path('vlans/edit/', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'), - path('vlans/delete/', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'), + path('vlans/', include(get_model_urls('ipam', 'vlan', detail=False))), path('vlans//', include(get_model_urls('ipam', 'vlan'))), - # VLAN Translation Policies - path('vlan-translation-policies/', views.VLANTranslationPolicyListView.as_view(), name='vlantranslationpolicy_list'), - path('vlan-translation-policies/add/', views.VLANTranslationPolicyEditView.as_view(), name='vlantranslationpolicy_add'), - path('vlan-translation-policies/import/', views.VLANTranslationPolicyBulkImportView.as_view(), name='vlantranslationpolicy_import'), - path('vlan-translation-policies/edit/', views.VLANTranslationPolicyBulkEditView.as_view(), name='vlantranslationpolicy_bulk_edit'), - path('vlan-translation-policies/delete/', views.VLANTranslationPolicyBulkDeleteView.as_view(), name='vlantranslationpolicy_bulk_delete'), + path('vlan-translation-policies/', include(get_model_urls('ipam', 'vlantranslationpolicy', detail=False))), path('vlan-translation-policies//', include(get_model_urls('ipam', 'vlantranslationpolicy'))), - # VLAN Translation Rules - path('vlan-translation-rules/', views.VLANTranslationRuleListView.as_view(), name='vlantranslationrule_list'), - path('vlan-translation-rules/add/', views.VLANTranslationRuleEditView.as_view(), name='vlantranslationrule_add'), - path('vlan-translation-rules/import/', views.VLANTranslationRuleBulkImportView.as_view(), name='vlantranslationrule_import'), - path('vlan-translation-rules/edit/', views.VLANTranslationRuleBulkEditView.as_view(), name='vlantranslationrule_bulk_edit'), - path('vlan-translation-rules/delete/', views.VLANTranslationRuleBulkDeleteView.as_view(), name='vlantranslationrule_bulk_delete'), + path('vlan-translation-rules/', include(get_model_urls('ipam', 'vlantranslationrule', detail=False))), path('vlan-translation-rules//', include(get_model_urls('ipam', 'vlantranslationrule'))), - # Service templates - path('service-templates/', views.ServiceTemplateListView.as_view(), name='servicetemplate_list'), - path('service-templates/add/', views.ServiceTemplateEditView.as_view(), name='servicetemplate_add'), - path('service-templates/import/', views.ServiceTemplateBulkImportView.as_view(), name='servicetemplate_import'), - path('service-templates/edit/', views.ServiceTemplateBulkEditView.as_view(), name='servicetemplate_bulk_edit'), - path('service-templates/delete/', views.ServiceTemplateBulkDeleteView.as_view(), name='servicetemplate_bulk_delete'), + path('service-templates/', include(get_model_urls('ipam', 'servicetemplate', detail=False))), path('service-templates//', include(get_model_urls('ipam', 'servicetemplate'))), - # Services - path('services/', views.ServiceListView.as_view(), name='service_list'), - path('services/add/', views.ServiceCreateView.as_view(), name='service_add'), - path('services/import/', views.ServiceBulkImportView.as_view(), name='service_import'), - path('services/edit/', views.ServiceBulkEditView.as_view(), name='service_bulk_edit'), - path('services/delete/', views.ServiceBulkDeleteView.as_view(), name='service_bulk_delete'), + path('services/', include(get_model_urls('ipam', 'service', detail=False))), path('services//', include(get_model_urls('ipam', 'service'))), ] diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index bbd19c433..327c05f3d 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -29,6 +29,7 @@ from .utils import add_requested_prefixes, add_available_ipaddresses, add_availa # VRFs # +@register_model_view(VRF, 'list', path='', detail=False) class VRFListView(generic.ObjectListView): queryset = VRF.objects.all() filterset = filtersets.VRFFilterSet @@ -57,6 +58,7 @@ class VRFView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(VRF, 'add', detail=False) @register_model_view(VRF, 'edit') class VRFEditView(generic.ObjectEditView): queryset = VRF.objects.all() @@ -68,11 +70,13 @@ class VRFDeleteView(generic.ObjectDeleteView): queryset = VRF.objects.all() +@register_model_view(VRF, 'import', detail=False) class VRFBulkImportView(generic.BulkImportView): queryset = VRF.objects.all() model_form = forms.VRFImportForm +@register_model_view(VRF, 'bulk_edit', path='edit', detail=False) class VRFBulkEditView(generic.BulkEditView): queryset = VRF.objects.all() filterset = filtersets.VRFFilterSet @@ -80,6 +84,7 @@ class VRFBulkEditView(generic.BulkEditView): form = forms.VRFBulkEditForm +@register_model_view(VRF, 'bulk_delete', path='delete', detail=False) class VRFBulkDeleteView(generic.BulkDeleteView): queryset = VRF.objects.all() filterset = filtersets.VRFFilterSet @@ -90,6 +95,7 @@ class VRFBulkDeleteView(generic.BulkDeleteView): # Route targets # +@register_model_view(RouteTarget, 'list', path='', detail=False) class RouteTargetListView(generic.ObjectListView): queryset = RouteTarget.objects.all() filterset = filtersets.RouteTargetFilterSet @@ -102,6 +108,7 @@ class RouteTargetView(generic.ObjectView): queryset = RouteTarget.objects.all() +@register_model_view(RouteTarget, 'add', detail=False) @register_model_view(RouteTarget, 'edit') class RouteTargetEditView(generic.ObjectEditView): queryset = RouteTarget.objects.all() @@ -113,11 +120,13 @@ class RouteTargetDeleteView(generic.ObjectDeleteView): queryset = RouteTarget.objects.all() +@register_model_view(RouteTarget, 'import', detail=False) class RouteTargetBulkImportView(generic.BulkImportView): queryset = RouteTarget.objects.all() model_form = forms.RouteTargetImportForm +@register_model_view(RouteTarget, 'bulk_edit', path='edit', detail=False) class RouteTargetBulkEditView(generic.BulkEditView): queryset = RouteTarget.objects.all() filterset = filtersets.RouteTargetFilterSet @@ -125,6 +134,7 @@ class RouteTargetBulkEditView(generic.BulkEditView): form = forms.RouteTargetBulkEditForm +@register_model_view(RouteTarget, 'bulk_delete', path='delete', detail=False) class RouteTargetBulkDeleteView(generic.BulkDeleteView): queryset = RouteTarget.objects.all() filterset = filtersets.RouteTargetFilterSet @@ -135,6 +145,7 @@ class RouteTargetBulkDeleteView(generic.BulkDeleteView): # RIRs # +@register_model_view(RIR, 'list', path='', detail=False) class RIRListView(generic.ObjectListView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') @@ -154,6 +165,7 @@ class RIRView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(RIR, 'add', detail=False) @register_model_view(RIR, 'edit') class RIREditView(generic.ObjectEditView): queryset = RIR.objects.all() @@ -165,11 +177,13 @@ class RIRDeleteView(generic.ObjectDeleteView): queryset = RIR.objects.all() +@register_model_view(RIR, 'import', detail=False) class RIRBulkImportView(generic.BulkImportView): queryset = RIR.objects.all() model_form = forms.RIRImportForm +@register_model_view(RIR, 'bulk_edit', path='edit', detail=False) class RIRBulkEditView(generic.BulkEditView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') @@ -179,6 +193,7 @@ class RIRBulkEditView(generic.BulkEditView): form = forms.RIRBulkEditForm +@register_model_view(RIR, 'bulk_delete', path='delete', detail=False) class RIRBulkDeleteView(generic.BulkDeleteView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') @@ -191,6 +206,7 @@ class RIRBulkDeleteView(generic.BulkDeleteView): # ASN ranges # +@register_model_view(ASNRange, 'list', path='', detail=False) class ASNRangeListView(generic.ObjectListView): queryset = ASNRange.objects.annotate_asn_counts() filterset = filtersets.ASNRangeFilterSet @@ -224,6 +240,7 @@ class ASNRangeASNsView(generic.ObjectChildrenView): ) +@register_model_view(ASNRange, 'add', detail=False) @register_model_view(ASNRange, 'edit') class ASNRangeEditView(generic.ObjectEditView): queryset = ASNRange.objects.all() @@ -235,11 +252,13 @@ class ASNRangeDeleteView(generic.ObjectDeleteView): queryset = ASNRange.objects.all() +@register_model_view(ASNRange, 'import', detail=False) class ASNRangeBulkImportView(generic.BulkImportView): queryset = ASNRange.objects.all() model_form = forms.ASNRangeImportForm +@register_model_view(ASNRange, 'bulk_edit', path='edit', detail=False) class ASNRangeBulkEditView(generic.BulkEditView): queryset = ASNRange.objects.annotate_asn_counts() filterset = filtersets.ASNRangeFilterSet @@ -247,6 +266,7 @@ class ASNRangeBulkEditView(generic.BulkEditView): form = forms.ASNRangeBulkEditForm +@register_model_view(ASNRange, 'bulk_delete', path='delete', detail=False) class ASNRangeBulkDeleteView(generic.BulkDeleteView): queryset = ASNRange.objects.annotate_asn_counts() filterset = filtersets.ASNRangeFilterSet @@ -257,6 +277,7 @@ class ASNRangeBulkDeleteView(generic.BulkDeleteView): # ASNs # +@register_model_view(ASN, 'list', path='', detail=False) class ASNListView(generic.ObjectListView): queryset = ASN.objects.annotate( site_count=count_related(Site, 'asns'), @@ -284,6 +305,7 @@ class ASNView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ASN, 'add', detail=False) @register_model_view(ASN, 'edit') class ASNEditView(generic.ObjectEditView): queryset = ASN.objects.all() @@ -295,11 +317,13 @@ class ASNDeleteView(generic.ObjectDeleteView): queryset = ASN.objects.all() +@register_model_view(ASN, 'import', detail=False) class ASNBulkImportView(generic.BulkImportView): queryset = ASN.objects.all() model_form = forms.ASNImportForm +@register_model_view(ASN, 'bulk_edit', path='edit', detail=False) class ASNBulkEditView(generic.BulkEditView): queryset = ASN.objects.annotate( site_count=count_related(Site, 'asns') @@ -309,6 +333,7 @@ class ASNBulkEditView(generic.BulkEditView): form = forms.ASNBulkEditForm +@register_model_view(ASN, 'bulk_delete', path='delete', detail=False) class ASNBulkDeleteView(generic.BulkDeleteView): queryset = ASN.objects.annotate( site_count=count_related(Site, 'asns') @@ -321,6 +346,7 @@ class ASNBulkDeleteView(generic.BulkDeleteView): # Aggregates # +@register_model_view(Aggregate, 'list', path='', detail=False) class AggregateListView(generic.ObjectListView): queryset = Aggregate.objects.annotate( child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) @@ -371,6 +397,7 @@ class AggregatePrefixesView(generic.ObjectChildrenView): } +@register_model_view(Aggregate, 'add', detail=False) @register_model_view(Aggregate, 'edit') class AggregateEditView(generic.ObjectEditView): queryset = Aggregate.objects.all() @@ -382,11 +409,13 @@ class AggregateDeleteView(generic.ObjectDeleteView): queryset = Aggregate.objects.all() +@register_model_view(Aggregate, 'import', detail=False) class AggregateBulkImportView(generic.BulkImportView): queryset = Aggregate.objects.all() model_form = forms.AggregateImportForm +@register_model_view(Aggregate, 'bulk_edit', path='edit', detail=False) class AggregateBulkEditView(generic.BulkEditView): queryset = Aggregate.objects.annotate( child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) @@ -396,6 +425,7 @@ class AggregateBulkEditView(generic.BulkEditView): form = forms.AggregateBulkEditForm +@register_model_view(Aggregate, 'bulk_delete', path='delete', detail=False) class AggregateBulkDeleteView(generic.BulkDeleteView): queryset = Aggregate.objects.annotate( child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) @@ -413,6 +443,7 @@ class AggregateContactsView(ObjectContactsView): # Prefix/VLAN roles # +@register_model_view(Role, 'list', path='', detail=False) class RoleListView(generic.ObjectListView): queryset = Role.objects.annotate( prefix_count=count_related(Prefix, 'role'), @@ -434,6 +465,7 @@ class RoleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Role, 'add', detail=False) @register_model_view(Role, 'edit') class RoleEditView(generic.ObjectEditView): queryset = Role.objects.all() @@ -445,11 +477,13 @@ class RoleDeleteView(generic.ObjectDeleteView): queryset = Role.objects.all() +@register_model_view(Role, 'import', detail=False) class RoleBulkImportView(generic.BulkImportView): queryset = Role.objects.all() model_form = forms.RoleImportForm +@register_model_view(Role, 'bulk_edit', path='edit', detail=False) class RoleBulkEditView(generic.BulkEditView): queryset = Role.objects.all() filterset = filtersets.RoleFilterSet @@ -457,6 +491,7 @@ class RoleBulkEditView(generic.BulkEditView): form = forms.RoleBulkEditForm +@register_model_view(Role, 'bulk_delete', path='delete', detail=False) class RoleBulkDeleteView(generic.BulkDeleteView): queryset = Role.objects.all() filterset = filtersets.RoleFilterSet @@ -467,6 +502,7 @@ class RoleBulkDeleteView(generic.BulkDeleteView): # Prefixes # +@register_model_view(Prefix, 'list', path='', detail=False) class PrefixListView(generic.ObjectListView): queryset = Prefix.objects.all() filterset = filtersets.PrefixFilterSet @@ -615,6 +651,7 @@ class PrefixIPAddressesView(generic.ObjectChildrenView): } +@register_model_view(Prefix, 'add', detail=False) @register_model_view(Prefix, 'edit') class PrefixEditView(generic.ObjectEditView): queryset = Prefix.objects.all() @@ -626,11 +663,13 @@ class PrefixDeleteView(generic.ObjectDeleteView): queryset = Prefix.objects.all() +@register_model_view(Prefix, 'import', detail=False) class PrefixBulkImportView(generic.BulkImportView): queryset = Prefix.objects.all() model_form = forms.PrefixImportForm +@register_model_view(Prefix, 'bulk_edit', path='edit', detail=False) class PrefixBulkEditView(generic.BulkEditView): queryset = Prefix.objects.prefetch_related('vrf__tenant') filterset = filtersets.PrefixFilterSet @@ -638,6 +677,7 @@ class PrefixBulkEditView(generic.BulkEditView): form = forms.PrefixBulkEditForm +@register_model_view(Prefix, 'bulk_delete', path='delete', detail=False) class PrefixBulkDeleteView(generic.BulkDeleteView): queryset = Prefix.objects.prefetch_related('vrf__tenant') filterset = filtersets.PrefixFilterSet @@ -653,6 +693,7 @@ class PrefixContactsView(ObjectContactsView): # IP Ranges # +@register_model_view(IPRange, 'list', path='', detail=False) class IPRangeListView(generic.ObjectListView): queryset = IPRange.objects.all() filterset = filtersets.IPRangeFilterSet @@ -704,6 +745,7 @@ class IPRangeIPAddressesView(generic.ObjectChildrenView): return parent.get_child_ips().restrict(request.user, 'view') +@register_model_view(IPRange, 'add', detail=False) @register_model_view(IPRange, 'edit') class IPRangeEditView(generic.ObjectEditView): queryset = IPRange.objects.all() @@ -715,11 +757,13 @@ class IPRangeDeleteView(generic.ObjectDeleteView): queryset = IPRange.objects.all() +@register_model_view(IPRange, 'import', detail=False) class IPRangeBulkImportView(generic.BulkImportView): queryset = IPRange.objects.all() model_form = forms.IPRangeImportForm +@register_model_view(IPRange, 'bulk_edit', path='edit', detail=False) class IPRangeBulkEditView(generic.BulkEditView): queryset = IPRange.objects.all() filterset = filtersets.IPRangeFilterSet @@ -727,6 +771,7 @@ class IPRangeBulkEditView(generic.BulkEditView): form = forms.IPRangeBulkEditForm +@register_model_view(IPRange, 'bulk_delete', path='delete', detail=False) class IPRangeBulkDeleteView(generic.BulkDeleteView): queryset = IPRange.objects.all() filterset = filtersets.IPRangeFilterSet @@ -742,6 +787,7 @@ class IPRangeContactsView(ObjectContactsView): # IP addresses # +@register_model_view(IPAddress, 'list', path='', detail=False) class IPAddressListView(generic.ObjectListView): queryset = IPAddress.objects.all() filterset = filtersets.IPAddressFilterSet @@ -788,6 +834,7 @@ class IPAddressView(generic.ObjectView): } +@register_model_view(IPAddress, 'add', detail=False) @register_model_view(IPAddress, 'edit') class IPAddressEditView(generic.ObjectEditView): queryset = IPAddress.objects.all() @@ -818,6 +865,7 @@ class IPAddressEditView(generic.ObjectEditView): # TODO: Standardize or remove this view +@register_model_view(IPAddress, 'assign', path='assign', detail=False) class IPAddressAssignView(generic.ObjectView): """ Search for IPAddresses to be assigned to an Interface. @@ -862,6 +910,7 @@ class IPAddressDeleteView(generic.ObjectDeleteView): queryset = IPAddress.objects.all() +@register_model_view(IPAddress, 'bulk_add', path='bulk-add', detail=False) class IPAddressBulkCreateView(generic.BulkCreateView): queryset = IPAddress.objects.all() form = forms.IPAddressBulkCreateForm @@ -870,11 +919,13 @@ class IPAddressBulkCreateView(generic.BulkCreateView): template_name = 'ipam/ipaddress_bulk_add.html' +@register_model_view(IPAddress, 'import', detail=False) class IPAddressBulkImportView(generic.BulkImportView): queryset = IPAddress.objects.all() model_form = forms.IPAddressImportForm +@register_model_view(IPAddress, 'bulk_edit', path='edit', detail=False) class IPAddressBulkEditView(generic.BulkEditView): queryset = IPAddress.objects.prefetch_related('vrf__tenant') filterset = filtersets.IPAddressFilterSet @@ -882,6 +933,7 @@ class IPAddressBulkEditView(generic.BulkEditView): form = forms.IPAddressBulkEditForm +@register_model_view(IPAddress, 'bulk_delete', path='delete', detail=False) class IPAddressBulkDeleteView(generic.BulkDeleteView): queryset = IPAddress.objects.prefetch_related('vrf__tenant') filterset = filtersets.IPAddressFilterSet @@ -915,6 +967,7 @@ class IPAddressContactsView(ObjectContactsView): # VLAN groups # +@register_model_view(VLANGroup, 'list', path='', detail=False) class VLANGroupListView(generic.ObjectListView): queryset = VLANGroup.objects.annotate_utilization() filterset = filtersets.VLANGroupFilterSet @@ -932,6 +985,7 @@ class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(VLANGroup, 'add', detail=False) @register_model_view(VLANGroup, 'edit') class VLANGroupEditView(generic.ObjectEditView): queryset = VLANGroup.objects.all() @@ -943,11 +997,13 @@ class VLANGroupDeleteView(generic.ObjectDeleteView): queryset = VLANGroup.objects.all() +@register_model_view(VLANGroup, 'import', detail=False) class VLANGroupBulkImportView(generic.BulkImportView): queryset = VLANGroup.objects.all() model_form = forms.VLANGroupImportForm +@register_model_view(VLANGroup, 'bulk_edit', path='edit', detail=False) class VLANGroupBulkEditView(generic.BulkEditView): queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags') filterset = filtersets.VLANGroupFilterSet @@ -955,6 +1011,7 @@ class VLANGroupBulkEditView(generic.BulkEditView): form = forms.VLANGroupBulkEditForm +@register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False) class VLANGroupBulkDeleteView(generic.BulkDeleteView): queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags') filterset = filtersets.VLANGroupFilterSet @@ -991,6 +1048,7 @@ class VLANGroupVLANsView(generic.ObjectChildrenView): # VLAN Translation Policies # +@register_model_view(VLANTranslationPolicy, 'list', path='', detail=False) class VLANTranslationPolicyListView(generic.ObjectListView): queryset = VLANTranslationPolicy.objects.all() filterset = filtersets.VLANTranslationPolicyFilterSet @@ -1012,6 +1070,7 @@ class VLANTranslationPolicyView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(VLANTranslationPolicy, 'add', detail=False) @register_model_view(VLANTranslationPolicy, 'edit') class VLANTranslationPolicyEditView(generic.ObjectEditView): queryset = VLANTranslationPolicy.objects.all() @@ -1023,11 +1082,13 @@ class VLANTranslationPolicyDeleteView(generic.ObjectDeleteView): queryset = VLANTranslationPolicy.objects.all() +@register_model_view(VLANTranslationPolicy, 'import', detail=False) class VLANTranslationPolicyBulkImportView(generic.BulkImportView): queryset = VLANTranslationPolicy.objects.all() model_form = forms.VLANTranslationPolicyImportForm +@register_model_view(VLANTranslationPolicy, 'bulk_edit', path='edit', detail=False) class VLANTranslationPolicyBulkEditView(generic.BulkEditView): queryset = VLANTranslationPolicy.objects.all() filterset = filtersets.VLANTranslationPolicyFilterSet @@ -1035,6 +1096,7 @@ class VLANTranslationPolicyBulkEditView(generic.BulkEditView): form = forms.VLANTranslationPolicyBulkEditForm +@register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False) class VLANTranslationPolicyBulkDeleteView(generic.BulkDeleteView): queryset = VLANTranslationPolicy.objects.all() filterset = filtersets.VLANTranslationPolicyFilterSet @@ -1045,6 +1107,7 @@ class VLANTranslationPolicyBulkDeleteView(generic.BulkDeleteView): # VLAN Translation Rules # +@register_model_view(VLANTranslationRule, 'list', path='', detail=False) class VLANTranslationRuleListView(generic.ObjectListView): queryset = VLANTranslationRule.objects.all() filterset = filtersets.VLANTranslationRuleFilterSet @@ -1062,6 +1125,7 @@ class VLANTranslationRuleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(VLANTranslationRule, 'add', detail=False) @register_model_view(VLANTranslationRule, 'edit') class VLANTranslationRuleEditView(generic.ObjectEditView): queryset = VLANTranslationRule.objects.all() @@ -1073,11 +1137,13 @@ class VLANTranslationRuleDeleteView(generic.ObjectDeleteView): queryset = VLANTranslationRule.objects.all() +@register_model_view(VLANTranslationRule, 'import', detail=False) class VLANTranslationRuleBulkImportView(generic.BulkImportView): queryset = VLANTranslationRule.objects.all() model_form = forms.VLANTranslationRuleImportForm +@register_model_view(VLANTranslationRule, 'bulk_edit', path='edit', detail=False) class VLANTranslationRuleBulkEditView(generic.BulkEditView): queryset = VLANTranslationRule.objects.all() filterset = filtersets.VLANTranslationRuleFilterSet @@ -1085,6 +1151,7 @@ class VLANTranslationRuleBulkEditView(generic.BulkEditView): form = forms.VLANTranslationRuleBulkEditForm +@register_model_view(VLANTranslationRule, 'bulk_delete', path='delete', detail=False) class VLANTranslationRuleBulkDeleteView(generic.BulkDeleteView): queryset = VLANTranslationRule.objects.all() filterset = filtersets.VLANTranslationRuleFilterSet @@ -1095,6 +1162,7 @@ class VLANTranslationRuleBulkDeleteView(generic.BulkDeleteView): # FHRP groups # +@register_model_view(FHRPGroup, 'list', path='', detail=False) class FHRPGroupListView(generic.ObjectListView): queryset = FHRPGroup.objects.annotate( member_count=count_related(FHRPGroupAssignment, 'group') @@ -1122,6 +1190,7 @@ class FHRPGroupView(generic.ObjectView): } +@register_model_view(FHRPGroup, 'add', detail=False) @register_model_view(FHRPGroup, 'edit') class FHRPGroupEditView(generic.ObjectEditView): queryset = FHRPGroup.objects.all() @@ -1149,11 +1218,13 @@ class FHRPGroupDeleteView(generic.ObjectDeleteView): queryset = FHRPGroup.objects.all() +@register_model_view(FHRPGroup, 'import', detail=False) class FHRPGroupBulkImportView(generic.BulkImportView): queryset = FHRPGroup.objects.all() model_form = forms.FHRPGroupImportForm +@register_model_view(FHRPGroup, 'bulk_edit', path='edit', detail=False) class FHRPGroupBulkEditView(generic.BulkEditView): queryset = FHRPGroup.objects.all() filterset = filtersets.FHRPGroupFilterSet @@ -1161,6 +1232,7 @@ class FHRPGroupBulkEditView(generic.BulkEditView): form = forms.FHRPGroupBulkEditForm +@register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False) class FHRPGroupBulkDeleteView(generic.BulkDeleteView): queryset = FHRPGroup.objects.all() filterset = filtersets.FHRPGroupFilterSet @@ -1171,6 +1243,7 @@ class FHRPGroupBulkDeleteView(generic.BulkDeleteView): # FHRP group assignments # +@register_model_view(FHRPGroupAssignment, 'add', detail=False) @register_model_view(FHRPGroupAssignment, 'edit') class FHRPGroupAssignmentEditView(generic.ObjectEditView): queryset = FHRPGroupAssignment.objects.all() @@ -1199,6 +1272,7 @@ class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView): # VLANs # +@register_model_view(VLAN, 'list', path='', detail=False) class VLANListView(generic.ObjectListView): queryset = VLAN.objects.all() filterset = filtersets.VLANFilterSet @@ -1257,6 +1331,7 @@ class VLANVMInterfacesView(generic.ObjectChildrenView): return parent.get_vminterfaces().restrict(request.user, 'view') +@register_model_view(VLAN, 'add', detail=False) @register_model_view(VLAN, 'edit') class VLANEditView(generic.ObjectEditView): queryset = VLAN.objects.all() @@ -1269,11 +1344,13 @@ class VLANDeleteView(generic.ObjectDeleteView): queryset = VLAN.objects.all() +@register_model_view(VLAN, 'import', detail=False) class VLANBulkImportView(generic.BulkImportView): queryset = VLAN.objects.all() model_form = forms.VLANImportForm +@register_model_view(VLAN, 'bulk_edit', path='edit', detail=False) class VLANBulkEditView(generic.BulkEditView): queryset = VLAN.objects.all() filterset = filtersets.VLANFilterSet @@ -1281,6 +1358,7 @@ class VLANBulkEditView(generic.BulkEditView): form = forms.VLANBulkEditForm +@register_model_view(VLAN, 'bulk_delete', path='delete', detail=False) class VLANBulkDeleteView(generic.BulkDeleteView): queryset = VLAN.objects.all() filterset = filtersets.VLANFilterSet @@ -1291,6 +1369,7 @@ class VLANBulkDeleteView(generic.BulkDeleteView): # Service templates # +@register_model_view(ServiceTemplate, 'list', path='', detail=False) class ServiceTemplateListView(generic.ObjectListView): queryset = ServiceTemplate.objects.all() filterset = filtersets.ServiceTemplateFilterSet @@ -1303,6 +1382,7 @@ class ServiceTemplateView(generic.ObjectView): queryset = ServiceTemplate.objects.all() +@register_model_view(ServiceTemplate, 'add', detail=False) @register_model_view(ServiceTemplate, 'edit') class ServiceTemplateEditView(generic.ObjectEditView): queryset = ServiceTemplate.objects.all() @@ -1314,11 +1394,13 @@ class ServiceTemplateDeleteView(generic.ObjectDeleteView): queryset = ServiceTemplate.objects.all() +@register_model_view(ServiceTemplate, 'import', detail=False) class ServiceTemplateBulkImportView(generic.BulkImportView): queryset = ServiceTemplate.objects.all() model_form = forms.ServiceTemplateImportForm +@register_model_view(ServiceTemplate, 'bulk_edit', path='edit', detail=False) class ServiceTemplateBulkEditView(generic.BulkEditView): queryset = ServiceTemplate.objects.all() filterset = filtersets.ServiceTemplateFilterSet @@ -1326,6 +1408,7 @@ class ServiceTemplateBulkEditView(generic.BulkEditView): form = forms.ServiceTemplateBulkEditForm +@register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False) class ServiceTemplateBulkDeleteView(generic.BulkDeleteView): queryset = ServiceTemplate.objects.all() filterset = filtersets.ServiceTemplateFilterSet @@ -1336,6 +1419,7 @@ class ServiceTemplateBulkDeleteView(generic.BulkDeleteView): # Services # +@register_model_view(Service, 'list', path='', detail=False) class ServiceListView(generic.ObjectListView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') filterset = filtersets.ServiceFilterSet @@ -1348,6 +1432,7 @@ class ServiceView(generic.ObjectView): queryset = Service.objects.all() +@register_model_view(Service, 'add', detail=False) class ServiceCreateView(generic.ObjectEditView): queryset = Service.objects.all() form = forms.ServiceCreateForm @@ -1364,11 +1449,13 @@ class ServiceDeleteView(generic.ObjectDeleteView): queryset = Service.objects.all() +@register_model_view(Service, 'import', detail=False) class ServiceBulkImportView(generic.BulkImportView): queryset = Service.objects.all() model_form = forms.ServiceImportForm +@register_model_view(Service, 'bulk_edit', path='edit', detail=False) class ServiceBulkEditView(generic.BulkEditView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') filterset = filtersets.ServiceFilterSet @@ -1376,6 +1463,7 @@ class ServiceBulkEditView(generic.BulkEditView): form = forms.ServiceBulkEditForm +@register_model_view(Service, 'bulk_delete', path='delete', detail=False) class ServiceBulkDeleteView(generic.BulkDeleteView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') filterset = filtersets.ServiceFilterSet diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index 637a40bf1..b8fbe7ad5 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -179,6 +179,8 @@ class BaseFilterSet(django_filters.FilterSet): # The filter field has been explicitly defined on the filterset class so we must manually # create the new filter with the same type because there is no guarantee the defined type # is the same as the default type for the field + if field is None: + raise ValueError('Invalid field name/lookup on {}: {}'.format(existing_filter_name, field_name)) resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid filter_cls = type(existing_filter) if lookup_expr == 'empty': @@ -262,7 +264,9 @@ class ChangeLoggedModelFilterSet(BaseFilterSet): action = { 'created_by_request': Q(action=ObjectChangeActionChoices.ACTION_CREATE), 'updated_by_request': Q(action=ObjectChangeActionChoices.ACTION_UPDATE), - 'modified_by_request': Q(action__in=[ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE]), + 'modified_by_request': Q( + action__in=[ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE] + ), }.get(name) request_id = value pks = ObjectChange.objects.filter( diff --git a/netbox/netbox/graphql/views.py b/netbox/netbox/graphql/views.py index 85a01f025..46a073c93 100644 --- a/netbox/netbox/graphql/views.py +++ b/netbox/netbox/graphql/views.py @@ -14,7 +14,6 @@ class NetBoxGraphQLView(GraphQLView): """ Extends strawberry's GraphQLView to support DRF's token-based authentication. """ - graphiql_template = 'graphiql.html' @csrf_exempt def dispatch(self, request, *args, **kwargs): diff --git a/netbox/netbox/jobs.py b/netbox/netbox/jobs.py index 965ebc9e9..3af3af554 100644 --- a/netbox/netbox/jobs.py +++ b/netbox/netbox/jobs.py @@ -91,6 +91,7 @@ class JobRunner(ABC): kwargs["job_timeout"] = job.object.python_class.job_timeout cls.enqueue( instance=job.object, + name=job.name, user=job.user, schedule_at=new_scheduled_time, interval=job.interval, diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index 737e399a5..ba20e5f98 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -88,6 +88,12 @@ DEVICES_MENU = Menu( get_model_item('dcim', 'manufacturer', _('Manufacturers')), ), ), + MenuGroup( + label=_('Addressing'), + items=( + get_model_item('dcim', 'macaddress', _('MAC Addresses')), + ), + ), MenuGroup( label=_('Device Components'), items=( @@ -278,6 +284,13 @@ CIRCUITS_MENU = Menu( get_model_item('circuits', 'circuittermination', _('Circuit Terminations')), ), ), + MenuGroup( + label=_('Virtual Circuits'), + items=( + get_model_item('circuits', 'virtualcircuit', _('Virtual Circuits')), + get_model_item('circuits', 'virtualcircuittermination', _('Virtual Circuit Terminations')), + ), + ), MenuGroup( label=_('Providers'), items=( diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index ee1420396..cf6e1f133 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -286,7 +286,8 @@ class ActionsColumn(tables.Column): if len(self.actions) == 1 or (self.split_actions and idx == 0): dropdown_class = attrs.css_class button = ( - f'' + f'' f'' ) @@ -303,7 +304,8 @@ class ActionsColumn(tables.Column): html += ( f'' f' {button}' - f' ' + f' ' f' {toggle_text}' f' ' f'' diff --git a/netbox/netbox/tests/test_views.py b/netbox/netbox/tests/test_views.py index ccba73baa..50cfa5755 100644 --- a/netbox/netbox/tests/test_views.py +++ b/netbox/netbox/tests/test_views.py @@ -1,7 +1,7 @@ import urllib.parse from django.urls import reverse -from django.test import override_settings +from django.test import Client, override_settings from dcim.models import Site from netbox.constants import EMPTY_TABLE_TEXT @@ -74,3 +74,21 @@ class SearchViewTestCase(TestCase): self.assertHttpStatus(response, 200) content = str(response.content) self.assertIn(EMPTY_TABLE_TEXT, content) + + +class MediaViewTestCase(TestCase): + + def test_media_login_required(self): + url = reverse('media', kwargs={'path': 'foo.txt'}) + response = Client().get(url) + + # Unauthenticated request should redirect to login page + self.assertHttpStatus(response, 302) + + @override_settings(LOGIN_REQUIRED=False) + def test_media_login_not_required(self): + url = reverse('media', kwargs={'path': 'foo.txt'}) + response = Client().get(url) + + # Unauthenticated request should return a 404 (not found) + self.assertHttpStatus(response, 404) diff --git a/netbox/netbox/urls.py b/netbox/netbox/urls.py index 08c9a46a8..90d70a357 100644 --- a/netbox/netbox/urls.py +++ b/netbox/netbox/urls.py @@ -2,7 +2,6 @@ from django.conf import settings from django.conf.urls import include from django.urls import path from django.views.decorators.cache import cache_page -from django.views.static import serve from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView from account.views import LoginView, LogoutView @@ -10,7 +9,7 @@ from netbox.api.views import APIRootView, StatusView from netbox.graphql.schema import schema from netbox.graphql.views import NetBoxGraphQLView from netbox.plugins.urls import plugin_patterns, plugin_api_patterns -from netbox.views import HomeView, StaticMediaFailureView, SearchView, htmx +from netbox.views import HomeView, MediaView, StaticMediaFailureView, SearchView, htmx _patterns = [ @@ -69,7 +68,7 @@ _patterns = [ path('graphql/', NetBoxGraphQLView.as_view(schema=schema), name='graphql'), # Serving static media in Django to pipe it through LoginRequiredMiddleware - path('media/', serve, {'document_root': settings.MEDIA_ROOT}), + path('media/', MediaView.as_view(), name='media'), path('media-failure/', StaticMediaFailureView.as_view(), name='media_failure'), # Plugins diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index d8115726c..456dd67d2 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -541,6 +541,17 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): def get_required_permission(self): return get_permission_for_model(self.queryset.model, 'change') + def post_save_operations(self, form, obj): + """ + This method is called for each object in _update_objects. Override to perform additional object-level + operations that are specific to a particular ModelForm. + """ + # Add/remove tags + if form.cleaned_data.get('add_tags', None): + obj.tags.add(*form.cleaned_data['add_tags']) + if form.cleaned_data.get('remove_tags', None): + obj.tags.remove(*form.cleaned_data['remove_tags']) + def _update_objects(self, form, request): custom_fields = getattr(form, 'custom_fields', {}) standard_fields = [ @@ -612,11 +623,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): elif form.cleaned_data[name]: getattr(obj, name).set(form.cleaned_data[name]) - # Add/remove tags - if form.cleaned_data.get('add_tags', None): - obj.tags.add(*form.cleaned_data['add_tags']) - if form.cleaned_data.get('remove_tags', None): - obj.tags.remove(*form.cleaned_data['remove_tags']) + self.post_save_operations(form, obj) # Rebuild the tree for MPTT models if issubclass(self.queryset.model, MPTTModel): @@ -691,7 +698,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): logger.debug("Form validation failed") else: - form = self.form(request.POST, initial=initial_data) + form = self.form(initial=initial_data) restrict_form_fields(form, request.user) # Retrieve objects being edited @@ -988,7 +995,8 @@ class BulkComponentCreateView(GetReturnURLMixin, BaseMultiObjectView): form.add_error(field, '{}: {}'.format(obj, ', '.join(e))) # Enforce object-level permissions - if self.queryset.filter(pk__in=[obj.pk for obj in new_components]).count() != len(new_components): + component_ids = [obj.pk for obj in new_components] + if self.queryset.filter(pk__in=component_ids).count() != len(new_components): raise PermissionsViolation except IntegrityError: diff --git a/netbox/netbox/views/generic/feature_views.py b/netbox/netbox/views/generic/feature_views.py index 49862e83f..1e17d5354 100644 --- a/netbox/netbox/views/generic/feature_views.py +++ b/netbox/netbox/views/generic/feature_views.py @@ -143,7 +143,12 @@ class ObjectJobsView(ConditionalLoginRequiredMixin, View): """ Render a list of all Job assigned to an object. For example: - path('data-sources//jobs/', ObjectJobsView.as_view(), name='datasource_jobs', kwargs={'model': DataSource}), + path( + 'data-sources//jobs/', + ObjectJobsView.as_view(), + name='datasource_jobs', + kwargs={'model': DataSource} + ) Attributes: base_template: The name of the template to extend. If not provided, "{app}/{model}.html" will be used. diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 0686e52b7..fb554ca4f 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -233,18 +233,23 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): form = self.form(instance=obj, initial=initial_data) restrict_form_fields(form, request.user) - # If this is an HTMX request, return only the rendered form HTML - if htmx_partial(request): - return render(request, self.htmx_template_name, { - 'model': model, - 'object': obj, - 'form': form, - }) - - return render(request, self.template_name, { + context = { 'model': model, 'object': obj, 'form': form, + } + + # If the form is being displayed within a "quick add" widget, + # use the appropriate template + if request.GET.get('_quickadd'): + return render(request, 'htmx/quick_add.html', context) + + # If this is an HTMX request, return only the rendered form HTML + if htmx_partial(request): + return render(request, self.htmx_template_name, context) + + return render(request, self.template_name, { + **context, 'return_url': self.get_return_url(request, obj), 'prerequisite_model': get_prerequisite_model(self.queryset), **self.get_extra_context(request, obj), @@ -259,6 +264,7 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): """ logger = logging.getLogger('netbox.views.ObjectEditView') obj = self.get_object(**kwargs) + model = self.queryset.model # Take a snapshot for change logging (if editing an existing object) if obj.pk and hasattr(obj, 'snapshot'): @@ -292,6 +298,12 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): msg = f'{msg} {obj}' messages.success(request, msg) + # Object was created via "quick add" modal + if '_quickadd' in request.POST: + return render(request, 'htmx/quick_add_created.html', { + 'object': obj, + }) + # If adding another object, redirect back to the edit form if '_addanother' in request.POST: redirect_url = request.path @@ -324,12 +336,19 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): else: logger.debug("Form validation failed") - return render(request, self.template_name, { + context = { + 'model': model, 'object': obj, 'form': form, 'return_url': self.get_return_url(request, obj), **self.get_extra_context(request, obj), - }) + } + + # Form was submitted via a "quick add" widget + if '_quickadd' in request.POST: + return render(request, 'htmx/quick_add.html', context) + + return render(request, self.template_name, context) class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): diff --git a/netbox/netbox/views/misc.py b/netbox/netbox/views/misc.py index c584e99e4..f28b0f7b1 100644 --- a/netbox/netbox/views/misc.py +++ b/netbox/netbox/views/misc.py @@ -8,6 +8,7 @@ from django.core.cache import cache from django.shortcuts import redirect, render from django.utils.translation import gettext_lazy as _ from django.views.generic import View +from django.views.static import serve from django_tables2 import RequestConfig from packaging import version @@ -23,6 +24,7 @@ from utilities.views import ConditionalLoginRequiredMixin __all__ = ( 'HomeView', + 'MediaView', 'SearchView', ) @@ -115,3 +117,11 @@ class SearchView(ConditionalLoginRequiredMixin, View): 'form': form, 'table': table, }) + + +class MediaView(ConditionalLoginRequiredMixin, View): + """ + Wrap Django's serve() view to enforce LOGIN_REQUIRED for static media. + """ + def get(self, request, path): + return serve(request, path, document_root=settings.MEDIA_ROOT) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 969d5c73a..5e24ee625 100644 Binary files a/netbox/project-static/dist/netbox.js and b/netbox/project-static/dist/netbox.js differ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 0f4ac63d3..a05e8edb5 100644 Binary files a/netbox/project-static/dist/netbox.js.map and b/netbox/project-static/dist/netbox.js.map differ diff --git a/netbox/project-static/package.json b/netbox/project-static/package.json index b4e3a04eb..0750f397b 100644 --- a/netbox/project-static/package.json +++ b/netbox/project-static/package.json @@ -30,7 +30,7 @@ "gridstack": "10.3.1", "htmx.org": "1.9.12", "query-string": "9.1.1", - "sass": "1.80.4", + "sass": "1.80.5", "tom-select": "2.3.1", "typeface-inter": "3.18.1", "typeface-roboto-mono": "1.1.13" diff --git a/netbox/project-static/src/buttons/reslug.ts b/netbox/project-static/src/buttons/reslug.ts index f445854c1..53c21b1f0 100644 --- a/netbox/project-static/src/buttons/reslug.ts +++ b/netbox/project-static/src/buttons/reslug.ts @@ -1,3 +1,5 @@ +import { getElements } from '../util'; + /** * Create a slug from any input string. * @@ -15,34 +17,30 @@ function slugify(slug: string, chars: number): string { } /** - * If a slug field exists, add event listeners to handle automatically generating its value. + * For any slug fields, add event listeners to handle automatically generating slug values. */ export function initReslug(): void { - const slugField = document.getElementById('id_slug') as HTMLInputElement; - const slugButton = document.getElementById('reslug') as HTMLButtonElement; - if (slugField === null || slugButton === null) { - return; - } - const sourceId = slugField.getAttribute('slug-source'); - const sourceField = document.getElementById(`id_${sourceId}`) as HTMLInputElement; + for (const slugButton of getElements('button#reslug')) { + const form = slugButton.form; + if (form == null) continue; + const slugField = form.querySelector('#id_slug') as HTMLInputElement; + if (slugField == null) continue; + const sourceId = slugField.getAttribute('slug-source'); + const sourceField = form.querySelector(`#id_${sourceId}`) as HTMLInputElement; - if (sourceField === null) { - console.error('Unable to find field for slug field.'); - return; - } + const slugLengthAttr = slugField.getAttribute('maxlength'); + let slugLength = 50; - const slugLengthAttr = slugField.getAttribute('maxlength'); - let slugLength = 50; - - if (slugLengthAttr) { - slugLength = Number(slugLengthAttr); - } - sourceField.addEventListener('blur', () => { - if (!slugField.value) { - slugField.value = slugify(sourceField.value, slugLength); + if (slugLengthAttr) { + slugLength = Number(slugLengthAttr); } - }); - slugButton.addEventListener('click', () => { - slugField.value = slugify(sourceField.value, slugLength); - }); + sourceField.addEventListener('blur', () => { + if (!slugField.value) { + slugField.value = slugify(sourceField.value, slugLength); + } + }); + slugButton.addEventListener('click', () => { + slugField.value = slugify(sourceField.value, slugLength); + }); + } } diff --git a/netbox/project-static/src/htmx.ts b/netbox/project-static/src/htmx.ts index f4092036b..6a772011b 100644 --- a/netbox/project-static/src/htmx.ts +++ b/netbox/project-static/src/htmx.ts @@ -4,11 +4,16 @@ import { initSelects } from './select'; import { initObjectSelector } from './objectSelector'; import { initBootstrap } from './bs'; import { initMessages } from './messages'; +import { initQuickAdd } from './quickAdd'; function initDepedencies(): void { - for (const init of [initButtons, initClipboard, initSelects, initObjectSelector, initBootstrap, initMessages]) { - init(); - } + initButtons(); + initClipboard(); + initSelects(); + initObjectSelector(); + initQuickAdd(); + initBootstrap(); + initMessages(); } /** diff --git a/netbox/project-static/src/quickAdd.ts b/netbox/project-static/src/quickAdd.ts new file mode 100644 index 000000000..e038f5d19 --- /dev/null +++ b/netbox/project-static/src/quickAdd.ts @@ -0,0 +1,39 @@ +import { Modal } from 'bootstrap'; + +function handleQuickAddObject(): void { + const quick_add = document.getElementById('quick-add-object'); + if (quick_add == null) return; + + const object_id = quick_add.getAttribute('data-object-id'); + if (object_id == null) return; + const object_repr = quick_add.getAttribute('data-object-repr'); + if (object_repr == null) return; + + const target_id = quick_add.getAttribute('data-target-id'); + if (target_id == null) return; + const target = document.getElementById(target_id); + if (target == null) return; + + //@ts-expect-error tomselect added on init + target.tomselect.addOption({ + id: object_id, + display: object_repr, + }); + //@ts-expect-error tomselect added on init + target.tomselect.addItem(object_id); + + const modal_element = document.getElementById('htmx-modal'); + if (modal_element) { + const modal = Modal.getInstance(modal_element); + if (modal) { + modal.hide(); + } + } +} + +export function initQuickAdd(): void { + const quick_add_modal = document.getElementById('htmx-modal-content'); + if (quick_add_modal) { + quick_add_modal.addEventListener('htmx:afterSwap', () => handleQuickAddObject()); + } +} diff --git a/netbox/project-static/yarn.lock b/netbox/project-static/yarn.lock index 9c57c5485..44c9d994d 100644 --- a/netbox/project-static/yarn.lock +++ b/netbox/project-static/yarn.lock @@ -2656,10 +2656,10 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -sass@1.80.4: - version "1.80.4" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.80.4.tgz#bc0418fd796cad2f1a1309d8b4d7fe44b7027de0" - integrity sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w== +sass@1.80.5: + version "1.80.5" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.80.5.tgz#0ba965223d44df22497f2966b498cf5c453fae8f" + integrity sha512-TQd2aoQl/+zsxRMEDSxVdpPIqeq9UFc6pr7PzkugiTx3VYCFPUaa3P4RrBQsqok4PO200Vkz0vXQBNlg7W907g== dependencies: "@parcel/watcher" "^2.4.1" chokidar "^4.0.0" diff --git a/netbox/release.yaml b/netbox/release.yaml index 63854ac33..fadb01274 100644 --- a/netbox/release.yaml +++ b/netbox/release.yaml @@ -1,3 +1,3 @@ -version: "4.1.5" +version: "4.1.7" edition: "Community" -published: "2024-10-28" +published: "2024-11-21" diff --git a/netbox/templates/circuits/providernetwork.html b/netbox/templates/circuits/providernetwork.html index 000548734..5fd92615d 100644 --- a/netbox/templates/circuits/providernetwork.html +++ b/netbox/templates/circuits/providernetwork.html @@ -50,6 +50,19 @@

    {% trans "Circuits" %}

    {% htmx_table 'circuits:circuit_list' provider_network_id=object.pk %} +
    +

    + {% trans "Virtual Circuits" %} + {% if perms.circuits.add_virtualcircuit %} + + {% endif %} +

    + {% htmx_table 'circuits:virtualcircuit_list' provider_network_id=object.pk %} +
    {% plugin_full_width_page object %} diff --git a/netbox/templates/circuits/virtualcircuit.html b/netbox/templates/circuits/virtualcircuit.html new file mode 100644 index 000000000..400f90524 --- /dev/null +++ b/netbox/templates/circuits/virtualcircuit.html @@ -0,0 +1,84 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} +{% load i18n %} + +{% block breadcrumbs %} + {{ block.super }} + + +{% endblock %} + +{% block content %} +
    +
    +
    +

    {% trans "Virtual circuit" %}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {% trans "Provider" %}{{ object.provider|linkify }}
    {% trans "Provider Network" %}{{ object.provider_network|linkify }}
    {% trans "Provider account" %}{{ object.provider_account|linkify|placeholder }}
    {% trans "Circuit ID" %}{{ object.cid }}
    {% trans "Status" %}{% badge object.get_status_display bg_color=object.get_status_color %}
    {% trans "Tenant" %} + {% if object.tenant.group %} + {{ object.tenant.group|linkify }} / + {% endif %} + {{ object.tenant|linkify|placeholder }} +
    {% trans "Description" %}{{ object.description|placeholder }}
    +
    + {% include 'inc/panels/tags.html' %} + {% plugin_left_page object %} +
    +
    + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    +
    +

    + {% trans "Terminations" %} + {% if perms.circuits.add_virtualcircuittermination %} + + {% endif %} +

    + {% htmx_table 'circuits:virtualcircuittermination_list' virtual_circuit_id=object.pk %} +
    + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/circuits/virtualcircuittermination.html b/netbox/templates/circuits/virtualcircuittermination.html new file mode 100644 index 000000000..c08e3c604 --- /dev/null +++ b/netbox/templates/circuits/virtualcircuittermination.html @@ -0,0 +1,81 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} +{% load i18n %} + +{% block breadcrumbs %} + {{ block.super }} + + + +{% endblock %} + +{% block content %} +
    +
    +
    +

    {% trans "Virtual Circuit Termination" %}

    + + + + + + + + + + + + + + + + + + + + + +
    {% trans "Provider" %}{{ object.virtual_circuit.provider|linkify }}
    {% trans "Provider Network" %}{{ object.virtual_circuit.provider_network|linkify }}
    {% trans "Provider account" %}{{ object.virtual_circuit.provider_account|linkify|placeholder }}
    {% trans "Virtual circuit" %}{{ object.virtual_circuit|linkify }}
    {% trans "Role" %}{% badge object.get_role_display bg_color=object.get_role_color %}
    +
    + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/custom_fields.html' %} + {% plugin_left_page object %} +
    +
    +
    +

    {% trans "Interface" %}

    + + + + + + + + + + + + + + + + + +
    {% trans "Device" %}{{ object.interface.device|linkify }}
    {% trans "Interface" %}{{ object.interface|linkify }}
    {% trans "Type" %}{{ object.interface.get_type_display }}
    {% trans "Description" %}{{ object.interface.description|placeholder }}
    +
    + {% plugin_right_page object %} +
    +
    +
    +
    + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/core/datasource.html b/netbox/templates/core/datasource.html index 1ce14451b..a5afedec6 100644 --- a/netbox/templates/core/datasource.html +++ b/netbox/templates/core/datasource.html @@ -87,7 +87,7 @@ {% for name, field in backend.parameters.items %} {{ field.label }} - {% if name in backend.sensitive_parameters and not perms.core.change_datasource %} + {% if name in backend.sensitive_parameters %} ******** {% else %} {{ object.parameters|get_key:name|placeholder }} diff --git a/netbox/templates/dcim/interface.html b/netbox/templates/dcim/interface.html index b18a6380b..b0d307bee 100644 --- a/netbox/templates/dcim/interface.html +++ b/netbox/templates/dcim/interface.html @@ -123,11 +123,24 @@ - + - + @@ -139,7 +152,41 @@
    {% trans "MAC Address" %}{{ object.mac_address|placeholder }} + {% if object.mac_address %} + {{ object.mac_address }} + {% trans "Primary" %} + {% else %} + {{ ''|placeholder }} + {% endif %} +
    {% trans "WWN" %}{{ object.wwn|placeholder }} + {% if object.wwn %} + {{ object.wwn }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
    {% trans "VRF" %}
    - {% if not object.is_virtual %} + {% if object.is_virtual and object.virtual_circuit_termination %} +
    +

    {% trans "Virtual Circuit" %}

    + + + + + + + + + + + + + + + + + + + + + +
    {% trans "Provider" %}{{ object.virtual_circuit_termination.virtual_circuit.provider|linkify }}
    {% trans "Provider Network" %}{{ object.virtual_circuit_termination.virtual_circuit.provider_network|linkify }}
    {% trans "Circuit ID" %}{{ object.virtual_circuit_termination.virtual_circuit|linkify }}
    {% trans "Role" %}{{ object.virtual_circuit_termination.get_role_display }}
    {% trans "Connections" %} + {% for termination in object.virtual_circuit_termination.peer_terminations %} + {{ termination.interface.parent_object }} + + {{ termination.interface }} + ({{ termination.get_role_display }}) + {% if not forloop.last %}
    {% endif %} + {% endfor %} +
    +
    + {% elif not object.is_virtual %}

    {% trans "Connection" %}

    {% if object.mark_connected %} @@ -350,7 +397,23 @@ {% endif %} {% htmx_table 'ipam:ipaddress_list' interface_id=object.pk %} - +
    + + +
    +
    +
    +

    + {% trans "MAC Addresses" %} + {% if perms.dcim.add_macaddress %} + + {% endif %} +

    + {% htmx_table 'dcim:macaddress_list' interface_id=object.pk %}
    diff --git a/netbox/templates/dcim/macaddress.html b/netbox/templates/dcim/macaddress.html new file mode 100644 index 000000000..6d7532e6d --- /dev/null +++ b/netbox/templates/dcim/macaddress.html @@ -0,0 +1,55 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} +{% load render_table from django_tables2 %} +{% load i18n %} + +{% block content %} +
    +
    +
    +

    {% trans "MAC Address" %}

    + + + + + + + + + + + + + + + + + +
    {% trans "MAC Address" %} + {{ object.mac_address|placeholder }} + {% copy_content object.pk prefix="macaddress_" %} +
    {% trans "Description" %}{{ object.description|placeholder }}
    {% trans "Assignment" %} + {% if object.assigned_object %} + {{ object.assigned_object.parent_object|linkify }} / + {{ object.assigned_object|linkify }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
    {% trans "Primary for interface" %}{% checkmark object.is_primary %}
    +
    + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/custom_fields.html' %} + {% plugin_left_page object %} +
    +
    + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/graphiql.html b/netbox/templates/graphql/graphiql.html similarity index 87% rename from netbox/templates/graphiql.html rename to netbox/templates/graphql/graphiql.html index 0281012dc..f50648f1f 100644 --- a/netbox/templates/graphiql.html +++ b/netbox/templates/graphql/graphiql.html @@ -1,15 +1,8 @@ +{% load static %} {% comment %} This template derives from the strawberry-graphql project: https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/static/graphiql.html {% endcomment %} - -{% load static %} @@ -112,10 +105,7 @@ add "&raw" to the end of the URL within a browser. headers["x-csrftoken"] = csrfToken; } - const subscriptionsEnabled = JSON.parse("{{ SUBSCRIPTION_ENABLED }}"); - const subscriptionUrl = subscriptionsEnabled - ? httpUrlToWebSockeUrl(fetchURL) - : null; + const subscriptionUrl = httpUrlToWebSockeUrl(fetchURL); const fetcher = GraphiQL.createFetcher({ url: fetchURL, diff --git a/netbox/templates/htmx/quick_add.html b/netbox/templates/htmx/quick_add.html new file mode 100644 index 000000000..9473e14a1 --- /dev/null +++ b/netbox/templates/htmx/quick_add.html @@ -0,0 +1,28 @@ +{% load form_helpers %} +{% load helpers %} +{% load i18n %} + + + diff --git a/netbox/templates/htmx/quick_add_created.html b/netbox/templates/htmx/quick_add_created.html new file mode 100644 index 000000000..3b1a24c48 --- /dev/null +++ b/netbox/templates/htmx/quick_add_created.html @@ -0,0 +1,22 @@ +{% load form_helpers %} +{% load helpers %} +{% load i18n %} + + + diff --git a/netbox/templates/virtualization/vminterface.html b/netbox/templates/virtualization/vminterface.html index 13cc8aa2f..88c9379cf 100644 --- a/netbox/templates/virtualization/vminterface.html +++ b/netbox/templates/virtualization/vminterface.html @@ -14,73 +14,85 @@ {% block content %}
    -
    -

    {% trans "Interface" %}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% trans "Virtual Machine" %}{{ object.virtual_machine|linkify }}
    {% trans "Name" %}{{ object.name }}
    {% trans "Enabled" %} - {% if object.enabled %} - - {% else %} - - {% endif %} -
    {% trans "Parent" %}{{ object.parent|linkify|placeholder }}
    {% trans "Bridge" %}{{ object.bridge|linkify|placeholder }}
    {% trans "VRF" %}{{ object.vrf|linkify|placeholder }}
    {% trans "Description" %}{{ object.description|placeholder }}
    {% trans "MTU" %}{{ object.mtu|placeholder }}
    {% trans "MAC Address" %}{{ object.mac_address|placeholder }}
    {% trans "802.1Q Mode" %}{{ object.get_mode_display|placeholder }}
    {% trans "Tunnel" %}{{ object.tunnel_termination.tunnel|linkify|placeholder }}
    {% trans "VLAN Translation" %}{{ object.vlan_translation_policy|linkify|placeholder }}
    -
    - {% include 'inc/panels/tags.html' %} - {% plugin_left_page object %} +
    +

    {% trans "Interface" %}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {% trans "Virtual Machine" %}{{ object.virtual_machine|linkify }}
    {% trans "Name" %}{{ object.name }}
    {% trans "Enabled" %} + {% if object.enabled %} + + {% else %} + + {% endif %} +
    {% trans "Parent" %}{{ object.parent|linkify|placeholder }}
    {% trans "Bridge" %}{{ object.bridge|linkify|placeholder }}
    {% trans "Description" %}{{ object.description|placeholder }}
    {% trans "MTU" %}{{ object.mtu|placeholder }}
    {% trans "802.1Q Mode" %}{{ object.get_mode_display|placeholder }}
    {% trans "Tunnel" %}{{ object.tunnel_termination.tunnel|linkify|placeholder }}
    -
    - {% include 'inc/panels/custom_fields.html' %} - {% include 'ipam/inc/panels/fhrp_groups.html' %} - {% plugin_right_page object %} + {% include 'inc/panels/tags.html' %} + {% plugin_left_page object %} +
    +
    + {% include 'inc/panels/custom_fields.html' %} +
    +

    {% trans "Addressing" %}

    + + + + + + + + + + + + + +
    {% trans "MAC Address" %} + {% if object.mac_address %} + {{ object.mac_address }} + {% trans "Primary" %} + {% else %} + {{ ''|placeholder }} + {% endif %} +
    {% trans "VRF" %}{{ object.vrf|linkify|placeholder }}
    {% trans "VLAN Translation" %}{{ object.vlan_translation_policy|linkify|placeholder }}
    + {% include 'ipam/inc/panels/fhrp_groups.html' %} + {% plugin_right_page object %} +
    @@ -99,6 +111,24 @@
    +
    +
    +
    +

    + {% trans "MAC Addresses" %} + {% if perms.ipam.add_macaddress %} + + {% endif %} +

    + {% htmx_table 'dcim:macaddress_list' vminterface_id=object.pk %} +
    +
    +
    {% include 'inc/panel_table.html' with table=vlan_table heading="VLANs" %} diff --git a/netbox/tenancy/forms/forms.py b/netbox/tenancy/forms/forms.py index 114253e7a..0edb36348 100644 --- a/netbox/tenancy/forms/forms.py +++ b/netbox/tenancy/forms/forms.py @@ -25,6 +25,7 @@ class TenancyForm(forms.Form): label=_('Tenant'), queryset=Tenant.objects.all(), required=False, + quick_add=True, query_params={ 'group_id': '$tenant_group' } diff --git a/netbox/tenancy/migrations/0001_squashed_0012.py b/netbox/tenancy/migrations/0001_squashed_0012.py index e8a028a92..8f3f74d9f 100644 --- a/netbox/tenancy/migrations/0001_squashed_0012.py +++ b/netbox/tenancy/migrations/0001_squashed_0012.py @@ -6,7 +6,6 @@ import taggit.managers class Migration(migrations.Migration): - initial = True dependencies = [ @@ -43,7 +42,16 @@ class Migration(migrations.Migration): ('rght', models.PositiveIntegerField(editable=False)), ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), ('level', models.PositiveIntegerField(editable=False)), - ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='tenancy.tenantgroup')), + ( + 'parent', + mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='tenancy.tenantgroup', + ), + ), ], options={ 'ordering': ['name'], @@ -60,7 +68,16 @@ class Migration(migrations.Migration): ('slug', models.SlugField(max_length=100, unique=True)), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), - ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tenants', to='tenancy.tenantgroup')), + ( + 'group', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='tenants', + to='tenancy.tenantgroup', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ diff --git a/netbox/tenancy/migrations/0002_squashed_0011.py b/netbox/tenancy/migrations/0002_squashed_0011.py index 8accd1da9..cfdcb58dd 100644 --- a/netbox/tenancy/migrations/0002_squashed_0011.py +++ b/netbox/tenancy/migrations/0002_squashed_0011.py @@ -7,7 +7,6 @@ import utilities.json class Migration(migrations.Migration): - replaces = [ ('tenancy', '0002_tenant_ordering'), ('tenancy', '0003_contacts'), @@ -18,7 +17,7 @@ class Migration(migrations.Migration): ('tenancy', '0008_unique_constraints'), ('tenancy', '0009_standardize_description_comments'), ('tenancy', '0010_tenant_relax_uniqueness'), - ('tenancy', '0011_contactassignment_tags') + ('tenancy', '0011_contactassignment_tags'), ] dependencies = [ @@ -37,7 +36,10 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=100, unique=True)), ('slug', models.SlugField(max_length=100, unique=True)), @@ -53,7 +55,10 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=100)), ('slug', models.SlugField(max_length=100)), @@ -62,7 +67,16 @@ class Migration(migrations.Migration): ('rght', models.PositiveIntegerField(editable=False)), ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), ('level', models.PositiveIntegerField(editable=False)), - ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='tenancy.contactgroup')), + ( + 'parent', + mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='tenancy.contactgroup', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -75,7 +89,10 @@ class Migration(migrations.Migration): fields=[ ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=100)), ('title', models.CharField(blank=True, max_length=100)), @@ -83,7 +100,16 @@ class Migration(migrations.Migration): ('email', models.EmailField(blank=True, max_length=254)), ('address', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), - ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contacts', to='tenancy.contactgroup')), + ( + 'group', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='contacts', + to='tenancy.contactgroup', + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ('link', models.URLField(blank=True)), ], @@ -125,9 +151,24 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('object_id', models.PositiveBigIntegerField()), ('priority', models.CharField(blank=True, max_length=50)), - ('contact', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assignments', to='tenancy.contact')), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), - ('role', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assignments', to='tenancy.contactrole')), + ( + 'contact', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='assignments', to='tenancy.contact' + ), + ), + ( + 'content_type', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + ( + 'role', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name='assignments', + to='tenancy.contactrole', + ), + ), ], options={ 'ordering': ('priority', 'contact'), @@ -140,11 +181,16 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='contactassignment', - constraint=models.UniqueConstraint(fields=('content_type', 'object_id', 'contact', 'role'), name='tenancy_contactassignment_unique_object_contact_role'), + constraint=models.UniqueConstraint( + fields=('content_type', 'object_id', 'contact', 'role'), + name='tenancy_contactassignment_unique_object_contact_role', + ), ), migrations.AddConstraint( model_name='contactgroup', - constraint=models.UniqueConstraint(fields=('parent', 'name'), name='tenancy_contactgroup_unique_parent_name'), + constraint=models.UniqueConstraint( + fields=('parent', 'name'), name='tenancy_contactgroup_unique_parent_name' + ), ), migrations.AddField( model_name='contact', @@ -163,19 +209,31 @@ class Migration(migrations.Migration): ), migrations.AddConstraint( model_name='tenant', - constraint=models.UniqueConstraint(fields=('group', 'name'), name='tenancy_tenant_unique_group_name', violation_error_message='Tenant name must be unique per group.'), + constraint=models.UniqueConstraint( + fields=('group', 'name'), + name='tenancy_tenant_unique_group_name', + violation_error_message='Tenant name must be unique per group.', + ), ), migrations.AddConstraint( model_name='tenant', - constraint=models.UniqueConstraint(condition=models.Q(('group__isnull', True)), fields=('name',), name='tenancy_tenant_unique_name'), + constraint=models.UniqueConstraint( + condition=models.Q(('group__isnull', True)), fields=('name',), name='tenancy_tenant_unique_name' + ), ), migrations.AddConstraint( model_name='tenant', - constraint=models.UniqueConstraint(fields=('group', 'slug'), name='tenancy_tenant_unique_group_slug', violation_error_message='Tenant slug must be unique per group.'), + constraint=models.UniqueConstraint( + fields=('group', 'slug'), + name='tenancy_tenant_unique_group_slug', + violation_error_message='Tenant slug must be unique per group.', + ), ), migrations.AddConstraint( model_name='tenant', - constraint=models.UniqueConstraint(condition=models.Q(('group__isnull', True)), fields=('slug',), name='tenancy_tenant_unique_slug'), + constraint=models.UniqueConstraint( + condition=models.Q(('group__isnull', True)), fields=('slug',), name='tenancy_tenant_unique_slug' + ), ), migrations.AddField( model_name='contactassignment', diff --git a/netbox/tenancy/migrations/0012_contactassignment_custom_fields.py b/netbox/tenancy/migrations/0012_contactassignment_custom_fields.py index ee6726822..7f681fd91 100644 --- a/netbox/tenancy/migrations/0012_contactassignment_custom_fields.py +++ b/netbox/tenancy/migrations/0012_contactassignment_custom_fields.py @@ -5,7 +5,6 @@ import utilities.json class Migration(migrations.Migration): - dependencies = [ ('tenancy', '0011_contactassignment_tags'), ] diff --git a/netbox/tenancy/migrations/0013_gfk_indexes.py b/netbox/tenancy/migrations/0013_gfk_indexes.py index dd23cefbb..9d58c8932 100644 --- a/netbox/tenancy/migrations/0013_gfk_indexes.py +++ b/netbox/tenancy/migrations/0013_gfk_indexes.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('tenancy', '0012_contactassignment_custom_fields'), ] diff --git a/netbox/tenancy/migrations/0014_contactassignment_ordering.py b/netbox/tenancy/migrations/0014_contactassignment_ordering.py index 66f08aa2a..5e2c39311 100644 --- a/netbox/tenancy/migrations/0014_contactassignment_ordering.py +++ b/netbox/tenancy/migrations/0014_contactassignment_ordering.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('tenancy', '0013_gfk_indexes'), ] diff --git a/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py b/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py index 58b14e10f..f2c1ce190 100644 --- a/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py +++ b/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('extras', '0111_rename_content_types'), @@ -25,16 +24,13 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='contactassignment', - index=models.Index( - fields=['object_type', 'object_id'], - name='tenancy_con_object__6f20f7_idx' - ), + index=models.Index(fields=['object_type', 'object_id'], name='tenancy_con_object__6f20f7_idx'), ), migrations.AddConstraint( model_name='contactassignment', constraint=models.UniqueConstraint( fields=('object_type', 'object_id', 'contact', 'role'), - name='tenancy_contactassignment_unique_object_contact_role' + name='tenancy_contactassignment_unique_object_contact_role', ), ), ] diff --git a/netbox/tenancy/migrations/0016_charfield_null_choices.py b/netbox/tenancy/migrations/0016_charfield_null_choices.py index 815a1bdf2..9f5016a13 100644 --- a/netbox/tenancy/migrations/0016_charfield_null_choices.py +++ b/netbox/tenancy/migrations/0016_charfield_null_choices.py @@ -11,7 +11,6 @@ def set_null_values(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('tenancy', '0015_contactassignment_rename_content_type'), ] @@ -22,8 +21,5 @@ class Migration(migrations.Migration): name='priority', field=models.CharField(blank=True, max_length=50, null=True), ), - migrations.RunPython( - code=set_null_values, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=set_null_values, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/tenancy/migrations/0017_natural_ordering.py b/netbox/tenancy/migrations/0017_natural_ordering.py index de1fb49aa..beb98d634 100644 --- a/netbox/tenancy/migrations/0017_natural_ordering.py +++ b/netbox/tenancy/migrations/0017_natural_ordering.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('tenancy', '0016_charfield_null_choices'), ('dcim', '0197_natural_sort_collation'), diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index ec73cac4a..005bcf737 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -2,6 +2,7 @@ from django.utils.translation import gettext_lazy as _ import django_tables2 as tables from netbox.tables import columns +from .template_code import * __all__ = ( 'ContactsColumnMixin', @@ -15,15 +16,7 @@ class TenantColumn(tables.TemplateColumn): """ Include the tenant description. """ - template_code = """ - {% if record.tenant %} - {{ record.tenant }} - {% elif record.vrf.tenant %} - {{ record.vrf.tenant }}* - {% else %} - — - {% endif %} - """ + template_code = TENANT_COLUMN def __init__(self, *args, **kwargs): super().__init__(template_code=self.template_code, *args, **kwargs) @@ -36,15 +29,7 @@ class TenantGroupColumn(tables.TemplateColumn): """ Include the tenant group description. """ - template_code = """ - {% if record.tenant and record.tenant.group %} - {{ record.tenant.group }} - {% elif record.vrf.tenant and record.vrf.tenant.group %} - {{ record.vrf.tenant.group }}* - {% else %} - — - {% endif %} - """ + template_code = TENANT_GROUP_COLUMN def __init__(self, accessor=tables.A('tenant__group'), *args, **kwargs): if 'verbose_name' not in kwargs: diff --git a/netbox/tenancy/tables/template_code.py b/netbox/tenancy/tables/template_code.py new file mode 100644 index 000000000..1d15a8708 --- /dev/null +++ b/netbox/tenancy/tables/template_code.py @@ -0,0 +1,19 @@ +TENANT_COLUMN = """ +{% if record.tenant %} + {{ record.tenant }} +{% elif record.vrf.tenant %} + {{ record.vrf.tenant }}* +{% else %} + — +{% endif %} +""" + +TENANT_GROUP_COLUMN = """ +{% if record.tenant and record.tenant.group %} + {{ record.tenant.group }} +{% elif record.vrf.tenant and record.vrf.tenant.group %} + {{ record.vrf.tenant.group }}* +{% else %} + — +{% endif %} +""" diff --git a/netbox/tenancy/tests/test_api.py b/netbox/tenancy/tests/test_api.py index 5a6fe0453..c32ad3826 100644 --- a/netbox/tenancy/tests/test_api.py +++ b/netbox/tenancy/tests/test_api.py @@ -239,9 +239,24 @@ class ContactAssignmentTest(APIViewTestCases.APIViewTestCase): ContactRole.objects.bulk_create(contact_roles) contact_assignments = ( - ContactAssignment(object=sites[0], contact=contacts[0], role=contact_roles[0], priority=ContactPriorityChoices.PRIORITY_PRIMARY), - ContactAssignment(object=sites[0], contact=contacts[1], role=contact_roles[1], priority=ContactPriorityChoices.PRIORITY_SECONDARY), - ContactAssignment(object=sites[0], contact=contacts[2], role=contact_roles[2], priority=ContactPriorityChoices.PRIORITY_TERTIARY), + ContactAssignment( + object=sites[0], + contact=contacts[0], + role=contact_roles[0], + priority=ContactPriorityChoices.PRIORITY_PRIMARY, + ), + ContactAssignment( + object=sites[0], + contact=contacts[1], + role=contact_roles[1], + priority=ContactPriorityChoices.PRIORITY_SECONDARY, + ), + ContactAssignment( + object=sites[0], + contact=contacts[2], + role=contact_roles[2], + priority=ContactPriorityChoices.PRIORITY_TERTIARY, + ), ) ContactAssignment.objects.bulk_create(contact_assignments) diff --git a/netbox/tenancy/urls.py b/netbox/tenancy/urls.py index ad9908c62..cd0caabdc 100644 --- a/netbox/tenancy/urls.py +++ b/netbox/tenancy/urls.py @@ -1,57 +1,27 @@ from django.urls import include, path from utilities.urls import get_model_urls -from . import views +from . import views # noqa F401 app_name = 'tenancy' urlpatterns = [ - # Tenant groups - path('tenant-groups/', views.TenantGroupListView.as_view(), name='tenantgroup_list'), - path('tenant-groups/add/', views.TenantGroupEditView.as_view(), name='tenantgroup_add'), - path('tenant-groups/import/', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'), - path('tenant-groups/edit/', views.TenantGroupBulkEditView.as_view(), name='tenantgroup_bulk_edit'), - path('tenant-groups/delete/', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'), + path('tenant-groups/', include(get_model_urls('tenancy', 'tenantgroup', detail=False))), path('tenant-groups//', include(get_model_urls('tenancy', 'tenantgroup'))), - # Tenants - path('tenants/', views.TenantListView.as_view(), name='tenant_list'), - path('tenants/add/', views.TenantEditView.as_view(), name='tenant_add'), - path('tenants/import/', views.TenantBulkImportView.as_view(), name='tenant_import'), - path('tenants/edit/', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'), - path('tenants/delete/', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'), + path('tenants/', include(get_model_urls('tenancy', 'tenant', detail=False))), path('tenants//', include(get_model_urls('tenancy', 'tenant'))), - # Contact groups - path('contact-groups/', views.ContactGroupListView.as_view(), name='contactgroup_list'), - path('contact-groups/add/', views.ContactGroupEditView.as_view(), name='contactgroup_add'), - path('contact-groups/import/', views.ContactGroupBulkImportView.as_view(), name='contactgroup_import'), - path('contact-groups/edit/', views.ContactGroupBulkEditView.as_view(), name='contactgroup_bulk_edit'), - path('contact-groups/delete/', views.ContactGroupBulkDeleteView.as_view(), name='contactgroup_bulk_delete'), + path('contact-groups/', include(get_model_urls('tenancy', 'contactgroup', detail=False))), path('contact-groups//', include(get_model_urls('tenancy', 'contactgroup'))), - # Contact roles - path('contact-roles/', views.ContactRoleListView.as_view(), name='contactrole_list'), - path('contact-roles/add/', views.ContactRoleEditView.as_view(), name='contactrole_add'), - path('contact-roles/import/', views.ContactRoleBulkImportView.as_view(), name='contactrole_import'), - path('contact-roles/edit/', views.ContactRoleBulkEditView.as_view(), name='contactrole_bulk_edit'), - path('contact-roles/delete/', views.ContactRoleBulkDeleteView.as_view(), name='contactrole_bulk_delete'), + path('contact-roles/', include(get_model_urls('tenancy', 'contactrole', detail=False))), path('contact-roles//', include(get_model_urls('tenancy', 'contactrole'))), - # Contacts - path('contacts/', views.ContactListView.as_view(), name='contact_list'), - path('contacts/add/', views.ContactEditView.as_view(), name='contact_add'), - path('contacts/import/', views.ContactBulkImportView.as_view(), name='contact_import'), - path('contacts/edit/', views.ContactBulkEditView.as_view(), name='contact_bulk_edit'), - path('contacts/delete/', views.ContactBulkDeleteView.as_view(), name='contact_bulk_delete'), + path('contacts/', include(get_model_urls('tenancy', 'contact', detail=False))), path('contacts//', include(get_model_urls('tenancy', 'contact'))), - # Contact assignments - path('contact-assignments/', views.ContactAssignmentListView.as_view(), name='contactassignment_list'), - path('contact-assignments/add/', views.ContactAssignmentEditView.as_view(), name='contactassignment_add'), - path('contact-assignments/import/', views.ContactAssignmentBulkImportView.as_view(), name='contactassignment_import'), - path('contact-assignments/edit/', views.ContactAssignmentBulkEditView.as_view(), name='contactassignment_bulk_edit'), - path('contact-assignments/delete/', views.ContactAssignmentBulkDeleteView.as_view(), name='contactassignment_bulk_delete'), + path('contact-assignments/', include(get_model_urls('tenancy', 'contactassignment', detail=False))), path('contact-assignments//', include(get_model_urls('tenancy', 'contactassignment'))), ] diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 96b2cb071..6f16842f6 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -37,11 +37,12 @@ class ObjectContactsView(generic.ObjectChildrenView): return table + # # Tenant groups # - +@register_model_view(TenantGroup, 'list', path='', detail=False) class TenantGroupListView(generic.ObjectListView): queryset = TenantGroup.objects.add_related_count( TenantGroup.objects.all(), @@ -67,6 +68,7 @@ class TenantGroupView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(TenantGroup, 'add', detail=False) @register_model_view(TenantGroup, 'edit') class TenantGroupEditView(generic.ObjectEditView): queryset = TenantGroup.objects.all() @@ -78,11 +80,13 @@ class TenantGroupDeleteView(generic.ObjectDeleteView): queryset = TenantGroup.objects.all() +@register_model_view(TenantGroup, 'import', detail=False) class TenantGroupBulkImportView(generic.BulkImportView): queryset = TenantGroup.objects.all() model_form = forms.TenantGroupImportForm +@register_model_view(TenantGroup, 'bulk_edit', path='edit', detail=False) class TenantGroupBulkEditView(generic.BulkEditView): queryset = TenantGroup.objects.add_related_count( TenantGroup.objects.all(), @@ -96,6 +100,7 @@ class TenantGroupBulkEditView(generic.BulkEditView): form = forms.TenantGroupBulkEditForm +@register_model_view(TenantGroup, 'bulk_delete', path='delete', detail=False) class TenantGroupBulkDeleteView(generic.BulkDeleteView): queryset = TenantGroup.objects.add_related_count( TenantGroup.objects.all(), @@ -112,6 +117,7 @@ class TenantGroupBulkDeleteView(generic.BulkDeleteView): # Tenants # +@register_model_view(Tenant, 'list', path='', detail=False) class TenantListView(generic.ObjectListView): queryset = Tenant.objects.all() filterset = filtersets.TenantFilterSet @@ -129,6 +135,7 @@ class TenantView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(Tenant, 'add', detail=False) @register_model_view(Tenant, 'edit') class TenantEditView(generic.ObjectEditView): queryset = Tenant.objects.all() @@ -140,11 +147,13 @@ class TenantDeleteView(generic.ObjectDeleteView): queryset = Tenant.objects.all() +@register_model_view(Tenant, 'import', detail=False) class TenantBulkImportView(generic.BulkImportView): queryset = Tenant.objects.all() model_form = forms.TenantImportForm +@register_model_view(Tenant, 'bulk_edit', path='edit', detail=False) class TenantBulkEditView(generic.BulkEditView): queryset = Tenant.objects.all() filterset = filtersets.TenantFilterSet @@ -152,6 +161,7 @@ class TenantBulkEditView(generic.BulkEditView): form = forms.TenantBulkEditForm +@register_model_view(Tenant, 'bulk_delete', path='delete', detail=False) class TenantBulkDeleteView(generic.BulkDeleteView): queryset = Tenant.objects.all() filterset = filtersets.TenantFilterSet @@ -167,6 +177,7 @@ class TenantContactsView(ObjectContactsView): # Contact groups # +@register_model_view(ContactGroup, 'list', path='', detail=False) class ContactGroupListView(generic.ObjectListView): queryset = ContactGroup.objects.add_related_count( ContactGroup.objects.all(), @@ -192,6 +203,7 @@ class ContactGroupView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ContactGroup, 'add', detail=False) @register_model_view(ContactGroup, 'edit') class ContactGroupEditView(generic.ObjectEditView): queryset = ContactGroup.objects.all() @@ -203,11 +215,13 @@ class ContactGroupDeleteView(generic.ObjectDeleteView): queryset = ContactGroup.objects.all() +@register_model_view(ContactGroup, 'import', detail=False) class ContactGroupBulkImportView(generic.BulkImportView): queryset = ContactGroup.objects.all() model_form = forms.ContactGroupImportForm +@register_model_view(ContactGroup, 'bulk_edit', path='edit', detail=False) class ContactGroupBulkEditView(generic.BulkEditView): queryset = ContactGroup.objects.add_related_count( ContactGroup.objects.all(), @@ -221,6 +235,7 @@ class ContactGroupBulkEditView(generic.BulkEditView): form = forms.ContactGroupBulkEditForm +@register_model_view(ContactGroup, 'bulk_delete', path='delete', detail=False) class ContactGroupBulkDeleteView(generic.BulkDeleteView): queryset = ContactGroup.objects.add_related_count( ContactGroup.objects.all(), @@ -237,6 +252,7 @@ class ContactGroupBulkDeleteView(generic.BulkDeleteView): # Contact roles # +@register_model_view(ContactRole, 'list', path='', detail=False) class ContactRoleListView(generic.ObjectListView): queryset = ContactRole.objects.all() filterset = filtersets.ContactRoleFilterSet @@ -254,6 +270,7 @@ class ContactRoleView(GetRelatedModelsMixin, generic.ObjectView): } +@register_model_view(ContactRole, 'add', detail=False) @register_model_view(ContactRole, 'edit') class ContactRoleEditView(generic.ObjectEditView): queryset = ContactRole.objects.all() @@ -265,11 +282,13 @@ class ContactRoleDeleteView(generic.ObjectDeleteView): queryset = ContactRole.objects.all() +@register_model_view(ContactRole, 'import', detail=False) class ContactRoleBulkImportView(generic.BulkImportView): queryset = ContactRole.objects.all() model_form = forms.ContactRoleImportForm +@register_model_view(ContactRole, 'bulk_edit', path='edit', detail=False) class ContactRoleBulkEditView(generic.BulkEditView): queryset = ContactRole.objects.all() filterset = filtersets.ContactRoleFilterSet @@ -277,6 +296,7 @@ class ContactRoleBulkEditView(generic.BulkEditView): form = forms.ContactRoleBulkEditForm +@register_model_view(ContactRole, 'bulk_delete', path='delete', detail=False) class ContactRoleBulkDeleteView(generic.BulkDeleteView): queryset = ContactRole.objects.all() filterset = filtersets.ContactRoleFilterSet @@ -287,6 +307,7 @@ class ContactRoleBulkDeleteView(generic.BulkDeleteView): # Contacts # +@register_model_view(Contact, 'list', path='', detail=False) class ContactListView(generic.ObjectListView): queryset = Contact.objects.annotate( assignment_count=count_related(ContactAssignment, 'contact') @@ -301,6 +322,7 @@ class ContactView(generic.ObjectView): queryset = Contact.objects.all() +@register_model_view(Contact, 'add', detail=False) @register_model_view(Contact, 'edit') class ContactEditView(generic.ObjectEditView): queryset = Contact.objects.all() @@ -312,11 +334,13 @@ class ContactDeleteView(generic.ObjectDeleteView): queryset = Contact.objects.all() +@register_model_view(Contact, 'import', detail=False) class ContactBulkImportView(generic.BulkImportView): queryset = Contact.objects.all() model_form = forms.ContactImportForm +@register_model_view(Contact, 'bulk_edit', path='edit', detail=False) class ContactBulkEditView(generic.BulkEditView): queryset = Contact.objects.annotate( assignment_count=count_related(ContactAssignment, 'contact') @@ -326,6 +350,7 @@ class ContactBulkEditView(generic.BulkEditView): form = forms.ContactBulkEditForm +@register_model_view(Contact, 'bulk_delete', path='delete', detail=False) class ContactBulkDeleteView(generic.BulkDeleteView): queryset = Contact.objects.annotate( assignment_count=count_related(ContactAssignment, 'contact') @@ -333,11 +358,12 @@ class ContactBulkDeleteView(generic.BulkDeleteView): filterset = filtersets.ContactFilterSet table = tables.ContactTable + # # Contact assignments # - +@register_model_view(ContactAssignment, 'list', path='', detail=False) class ContactAssignmentListView(generic.ObjectListView): queryset = ContactAssignment.objects.all() filterset = filtersets.ContactAssignmentFilterSet @@ -351,6 +377,7 @@ class ContactAssignmentListView(generic.ObjectListView): } +@register_model_view(ContactAssignment, 'add', detail=False) @register_model_view(ContactAssignment, 'edit') class ContactAssignmentEditView(generic.ObjectEditView): queryset = ContactAssignment.objects.all() @@ -370,6 +397,13 @@ class ContactAssignmentEditView(generic.ObjectEditView): } +@register_model_view(ContactAssignment, 'import', detail=False) +class ContactAssignmentBulkImportView(generic.BulkImportView): + queryset = ContactAssignment.objects.all() + model_form = forms.ContactAssignmentImportForm + + +@register_model_view(ContactAssignment, 'bulk_edit', path='edit', detail=False) class ContactAssignmentBulkEditView(generic.BulkEditView): queryset = ContactAssignment.objects.all() filterset = filtersets.ContactAssignmentFilterSet @@ -377,11 +411,7 @@ class ContactAssignmentBulkEditView(generic.BulkEditView): form = forms.ContactAssignmentBulkEditForm -class ContactAssignmentBulkImportView(generic.BulkImportView): - queryset = ContactAssignment.objects.all() - model_form = forms.ContactAssignmentImportForm - - +@register_model_view(ContactAssignment, 'bulk_delete', path='delete', detail=False) class ContactAssignmentBulkDeleteView(generic.BulkDeleteView): queryset = ContactAssignment.objects.all() filterset = filtersets.ContactAssignmentFilterSet diff --git a/netbox/translations/cs/LC_MESSAGES/django.mo b/netbox/translations/cs/LC_MESSAGES/django.mo index df95c667c..2fb886a1a 100644 Binary files a/netbox/translations/cs/LC_MESSAGES/django.mo and b/netbox/translations/cs/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/cs/LC_MESSAGES/django.po b/netbox/translations/cs/LC_MESSAGES/django.po index 2f557dcc9..de92208ff 100644 --- a/netbox/translations/cs/LC_MESSAGES/django.po +++ b/netbox/translations/cs/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Pavel Valach, 2024\n" "Language-Team: Czech (https://app.transifex.com/netbox-community/teams/178115/cs/)\n" @@ -84,8 +84,8 @@ msgid "Your password has been changed successfully." msgstr "Vaše heslo bylo úspěšně změněno." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Plánované" @@ -96,7 +96,7 @@ msgstr "Zajišťování" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -106,7 +106,7 @@ msgid "Active" msgstr "Aktivní" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Vypnuto" @@ -119,7 +119,7 @@ msgstr "Zrušení přidělování" msgid "Decommissioned" msgstr "Vyřazeno z provozu" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primární" @@ -178,8 +178,8 @@ msgstr "Skupina stránek (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -344,7 +344,7 @@ msgstr "Skupina okruhů (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -356,21 +356,21 @@ msgstr "ASN" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -411,7 +411,7 @@ msgstr "ASN" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -478,9 +478,9 @@ msgid "Service ID" msgstr "ID služby" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -497,11 +497,11 @@ msgstr "Barva" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -546,11 +546,11 @@ msgstr "Účet poskytovatele" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -577,7 +577,7 @@ msgstr "Účet poskytovatele" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -602,10 +602,10 @@ msgstr "Stav" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -709,11 +709,11 @@ msgstr "Rychlost portu (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Odchozí rychlost (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Označit jako zapojené" @@ -791,9 +791,9 @@ msgid "Provider network" msgstr "Síť poskytovatele" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -840,8 +840,8 @@ msgid "Contacts" msgstr "Kontakty" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -864,7 +864,7 @@ msgid "Region" msgstr "Region" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -882,7 +882,7 @@ msgstr "Skupina stránek" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -917,16 +917,17 @@ msgstr "Účet" msgid "Term Side" msgstr "Strana termínu" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Přiřazení" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -992,7 +993,7 @@ msgstr "Jedinečné ID obvodu" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1130,7 +1131,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1241,7 +1242,7 @@ msgstr "sítě poskytovatelů" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1378,7 +1379,7 @@ msgstr "Dokončeno" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Neuspěl" @@ -1525,8 +1526,8 @@ msgid "User name" msgstr "Uživatelské jméno" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1626,7 +1627,7 @@ msgid "Completed before" msgstr "Dokončeno dříve" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1687,9 +1688,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Výšky stojanů" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Napájení" @@ -2218,11 +2219,11 @@ msgstr "Práce {id} byl zastaven." msgid "Failed to stop job {id}" msgstr "Nepodařilo se zastavit úlohu {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Katalog pluginů nelze načíst" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} nenalezeno" @@ -2240,7 +2241,7 @@ msgid "Staging" msgstr "Inscenace" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Vyřazení z provozu" @@ -2300,7 +2301,7 @@ msgstr "Zastaralé" msgid "Millimeters" msgstr "Milimetry" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "palce" @@ -2312,8 +2313,8 @@ msgstr "Zepředu dozadu" msgid "Rear to front" msgstr "Zezadu dopředu" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2387,7 +2388,7 @@ msgstr "Zdola nahoru" msgid "Top to bottom" msgstr "Nahoru dolů" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "pasivní" @@ -2415,8 +2416,8 @@ msgstr "Mezinárodní/ITA" msgid "Proprietary" msgstr "Proprietární" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Ostatní" @@ -2429,22 +2430,22 @@ msgstr "ITA/Mezinárodní" msgid "Physical" msgstr "Fyzické" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtuální" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Bezdrátové" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Virtuální rozhraní" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2454,155 +2455,155 @@ msgstr "Virtuální rozhraní" msgid "Bridge" msgstr "Most" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Agregační skupina (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (pevný)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modulární)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (propojovací deska)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Buněčný" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Sériový" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Koaxiální" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Stohování" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Poloviční" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Plný" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Auto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Přístup" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Označeno" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Označeno (Vše)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Norma IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Pasivní 24V (2 páry)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Pasivní 24V (4 páry)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Pasivní 48V (2 páry)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Pasivní 48V (4 páry)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "měď" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Optická vlákna" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Vlákno" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Připojeno" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometry" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Metry" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centimetry" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Míle" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Stopy" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogramy" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramy" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "libry" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Unce" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundantní" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Jednofázový" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Třífázový" @@ -2835,7 +2836,7 @@ msgstr "Skupina clusteru (ID)" msgid "Device model (slug)" msgstr "Model zařízení (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Je plná hloubka" @@ -2951,7 +2952,7 @@ msgstr "Přiřazená VLAN" msgid "Assigned VID" msgstr "Přiřazené VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3112,27 +3113,27 @@ msgstr "" "Podporovány jsou alfanumerické rozsahy. (Musí odpovídat počtu vytvořených " "jmen.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Kontaktní jméno" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Kontaktní telefon" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Kontaktní e-mail" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Časové pásmo" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3155,51 +3156,51 @@ msgstr "Časové pásmo" msgid "Manufacturer" msgstr "Výrobce" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Tvarový faktor" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Šířka" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Výška (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Sestupné jednotky" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Vnější šířka" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Vnější hloubka" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Vnější jednotka" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Hloubka montáže" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3220,13 +3221,13 @@ msgstr "Hloubka montáže" msgid "Weight" msgstr "Hmotnost" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Max. hmotnost" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3234,31 +3235,31 @@ msgstr "Max. hmotnost" msgid "Weight unit" msgstr "Jednotka hmotnosti" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Typ stojanu" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Vnější rozměry" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Rozměry" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Číslování" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3298,21 +3299,21 @@ msgstr "Číslování" msgid "Role" msgstr "Role" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Sériové číslo" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Inventární číslo" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3322,7 +3323,7 @@ msgstr "Inventární číslo" msgid "Airflow" msgstr "Proudění vzduchu" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3342,7 +3343,7 @@ msgstr "Proudění vzduchu" msgid "Rack" msgstr "Stojan" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3351,49 +3352,49 @@ msgstr "Stojan" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Výchozí platforma" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Číslo dílu" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Výška U pozic" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Vyloučit z využití" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Typ zařízení" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Typ modulu" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Šasi" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Role virtuálního počítače" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3406,19 +3407,19 @@ msgstr "Role virtuálního počítače" msgid "Config template" msgstr "Konfigurační šablona" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Typ zařízení" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Role zařízení" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3432,8 +3433,28 @@ msgstr "Role zařízení" msgid "Platform" msgstr "Nástupiště" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Klastr" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3490,22 +3511,27 @@ msgstr "Nástupiště" msgid "Device" msgstr "Zařízení" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Konfigurace" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualizace" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Typ modulu" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3517,82 +3543,82 @@ msgstr "Typ modulu" msgid "Label" msgstr "Štítek" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Délka" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Jednotka délky" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Doména" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Napájecí panel" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Zdroj" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fáze" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Napětí" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Proud" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Maximální využití" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maximální příkon" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maximální příkon (W)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Přidělený příkon" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Přidělený příkon (W)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Napájecí port" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Napájecí větev" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Pouze správa" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3600,7 +3626,7 @@ msgstr "Pouze správa" msgid "PoE mode" msgstr "Režim PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3608,12 +3634,12 @@ msgstr "Režim PoE" msgid "PoE type" msgstr "Typ PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Bezdrátová role" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3623,16 +3649,16 @@ msgstr "Bezdrátová role" msgid "Module" msgstr "Modul" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "Agregační skupina" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Kontexty virtuálních zařízení" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3641,7 +3667,7 @@ msgstr "Kontexty virtuálních zařízení" msgid "Speed" msgstr "Rychlost" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3652,36 +3678,44 @@ msgstr "Rychlost" msgid "Mode" msgstr "Režim" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Skupina VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "Neznačené VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Označené VLAN" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Skupina bezdrátových sítí" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Bezdrátové LAN sítě" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3689,33 +3723,37 @@ msgstr "Bezdrátové LAN sítě" msgid "Addressing" msgstr "Adresování" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operace" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Související rozhraní" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Přepínání 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Pro přiřazení sítí VLAN musí být zadán režim rozhraní" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Přístupovému rozhraní nelze přiřadit označené sítě VLAN." @@ -3856,26 +3894,6 @@ msgstr "Přiřazená platforma" msgid "Virtual chassis" msgstr "Virtuální podvozek" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Klastr" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Virtualizační klastr" @@ -6556,31 +6574,31 @@ msgstr "Při vykreslování šablony došlo k chybě: {error}" msgid "Virtual Machines" msgstr "Virtuální stroje" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Nainstalované zařízení {device} v zátoce {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Odstraněné zařízení {device} od zátoky {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Děti" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Přidán člen {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Nelze odebrat hlavní zařízení {device} z virtuálního podvozku." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Odstraněno {device} z virtuálního šasi {chassis}" @@ -7513,19 +7531,19 @@ msgstr "Naplánujte spuštění skriptu na nastavený čas" msgid "Interval at which this script is re-run (in minutes)" msgstr "Interval, ve kterém je tento skript znovu spuštěn (v minutách)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Změny v databázi byly automaticky vráceny." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Skript byl přerušen s chybou: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Došlo k výjimce: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Změny databáze byly vráceny kvůli chybě." @@ -8833,7 +8851,7 @@ msgstr "Skupina VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9089,7 +9107,7 @@ msgstr "Přiřazeno k rozhraní" msgid "DNS Name" msgstr "Název DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9099,7 +9117,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "Obsahuje VLAN ID" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "ID VLAN" @@ -9550,40 +9568,48 @@ msgstr "Nelze nastavit scope_type bez scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Nelze nastavit scope_id bez scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Rozsahy se nemohou překrývat." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Maximální dětský VID musí být větší nebo roven minimálnímu dětskému VID " -"({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Konkrétní místo, ke kterému je tato VLAN přiřazena (pokud existuje)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Skupina VLAN (volitelné)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Numerické ID VLAN (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Provozní stav této VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Primární funkce této VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9592,7 +9618,7 @@ msgstr "" "VLAN je přiřazena ke skupině {group} (oblast působnosti: {scope}); nelze " "také přiřadit k webu {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID musí být v rozmezí {ranges} pro sítě VLAN ve skupině {group}" @@ -10333,10 +10359,6 @@ msgstr "Zásady protokolu IPsec" msgid "IPSec Profiles" msgstr "Profily IPsec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualizace" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10737,19 +10759,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Řádek {i}: Objekt s ID {id} neexistuje" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Ne {object_type} Byly vybrány." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Přejmenováno {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Vymazáno {count} {object_type}" @@ -10781,7 +10803,7 @@ msgstr "Synchronizováno {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} musí implementovat get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12635,7 +12657,7 @@ msgid "You do not have permission to run scripts" msgstr "Nemáte oprávnění spouštět skripty" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Spustit skript" @@ -12647,27 +12669,32 @@ msgstr "Chyba při načítání skriptu" msgid "Script no longer exists in the source file." msgstr "Skript již ve zdrojovém souboru neexistuje." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Poslední běh" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Skript již není přítomen ve zdrojovém souboru" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Nikdy" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Spustit znovu" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Nenalezeny žádné skripty" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14505,13 +14532,13 @@ msgid "Memory (MB)" msgstr "Paměť (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disk (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Velikost (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/da/LC_MESSAGES/django.mo b/netbox/translations/da/LC_MESSAGES/django.mo index 2390fc9f1..338255ed6 100644 Binary files a/netbox/translations/da/LC_MESSAGES/django.mo and b/netbox/translations/da/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/da/LC_MESSAGES/django.po b/netbox/translations/da/LC_MESSAGES/django.po index e569dd86b..2ab752fd7 100644 --- a/netbox/translations/da/LC_MESSAGES/django.po +++ b/netbox/translations/da/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Danish (https://app.transifex.com/netbox-community/teams/178115/da/)\n" @@ -85,8 +85,8 @@ msgid "Your password has been changed successfully." msgstr "Din adgangskode er blevet ændret." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planlagt" @@ -97,7 +97,7 @@ msgstr "Opretter" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -107,7 +107,7 @@ msgid "Active" msgstr "Aktiv" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Offline" @@ -120,7 +120,7 @@ msgstr "Nedlægger" msgid "Decommissioned" msgstr "Nedlagt" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primær" @@ -179,8 +179,8 @@ msgstr "Områdegruppe (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -345,7 +345,7 @@ msgstr "Kredsløbsgruppe (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -357,21 +357,21 @@ msgstr "ASN'er" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -412,7 +412,7 @@ msgstr "ASN'er" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -479,9 +479,9 @@ msgid "Service ID" msgstr "Tjeneste-id" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -498,11 +498,11 @@ msgstr "Farve" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -547,11 +547,11 @@ msgstr "Leverandørkonto" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -578,7 +578,7 @@ msgstr "Leverandørkonto" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -603,10 +603,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -710,11 +710,11 @@ msgstr "Porthastighed (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Opstrøms hastighed (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Marker tilsluttet" @@ -792,9 +792,9 @@ msgid "Provider network" msgstr "Leverandørnetværk" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -841,8 +841,8 @@ msgid "Contacts" msgstr "Kontakter" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -865,7 +865,7 @@ msgid "Region" msgstr "Regionen" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -883,7 +883,7 @@ msgstr "Områdegruppe" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -918,16 +918,17 @@ msgstr "Konto" msgid "Term Side" msgstr "Termside" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Opgave" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -993,7 +994,7 @@ msgstr "Unikt kredsløbs-ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1132,7 +1133,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1243,7 +1244,7 @@ msgstr "leverandørnetværk" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1380,7 +1381,7 @@ msgstr "Afsluttet" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Mislykkedes" @@ -1527,8 +1528,8 @@ msgid "User name" msgstr "Brugernavn" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1628,7 +1629,7 @@ msgid "Completed before" msgstr "Færdiggjort før" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1688,9 +1689,9 @@ msgstr "Skal uploade en fil eller vælge en datafil, der skal synkroniseres" msgid "Rack Elevations" msgstr "Rackhøjder" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Strøm" @@ -2221,11 +2222,11 @@ msgstr "Job {id} er blevet stoppet." msgid "Failed to stop job {id}" msgstr "Det lykkedes ikke at stoppe jobbet {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Plugin-kataloget kunne ikke indlæses" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} ikke fundet" @@ -2243,7 +2244,7 @@ msgid "Staging" msgstr "Iscenesættelse" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Nedlæggelse" @@ -2303,7 +2304,7 @@ msgstr "Forældet" msgid "Millimeters" msgstr "Millimeter" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Tommer" @@ -2315,8 +2316,8 @@ msgstr "Foran til bag" msgid "Rear to front" msgstr "Bagsiden til forsiden" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2390,7 +2391,7 @@ msgstr "Bund til top" msgid "Top to bottom" msgstr "Top til bund" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passiv" @@ -2418,8 +2419,8 @@ msgstr "International/ITA" msgid "Proprietary" msgstr "Proprietær" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Andet" @@ -2432,22 +2433,22 @@ msgstr "ITA/International" msgid "Physical" msgstr "Fysisk" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtuel" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Trådløs" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Virtuelle grænseflader" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2457,155 +2458,155 @@ msgstr "Virtuelle grænseflader" msgid "Bridge" msgstr "Bro" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Link Aggregation Group (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fast)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modulopbygget)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (bagplan)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Cellulær" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Seriel" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Koaksial" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Stabling" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Halvdelen" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Fuld" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Auto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Adgang" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Markeret" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Tagget (Alle)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE-standard" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Passiv 24V (2-par)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Passiv 24V (4-par)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Passiv 48V (2-par)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Passiv 48V (4-par)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Kobber" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Fiberoptisk" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fiber" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Tilsluttet" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometer" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Meter" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centimeter" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Mil" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Fod" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogram" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gram" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "pund" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Ounce" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundant" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Enkeltfase" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Trefaset" @@ -2838,7 +2839,7 @@ msgstr "Klyngegruppe (ID)" msgid "Device model (slug)" msgstr "Enhedsmodel (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Er fuld dybde" @@ -2954,7 +2955,7 @@ msgstr "Tildelt VLAN" msgid "Assigned VID" msgstr "Tildelt VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3115,27 +3116,27 @@ msgstr "" "Alfanumeriske intervaller understøttes. (Skal svare til antallet af navne, " "der oprettes.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Kontaktens navn" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Kontakt telefon" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Kontakt E-mail" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Tidszone" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3158,51 +3159,51 @@ msgstr "Tidszone" msgid "Manufacturer" msgstr "Producent" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Formfaktor" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Bredde" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Højde (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Faldende enheder" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Udvendig bredde" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Ydre dybde" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Ydre enhed" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Monteringsdybde" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3223,13 +3224,13 @@ msgstr "Monteringsdybde" msgid "Weight" msgstr "Vægt" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Maks. Vægt" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3237,31 +3238,31 @@ msgstr "Maks. Vægt" msgid "Weight unit" msgstr "Vægtenhed" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Racktype" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Udvendige mål" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensioner" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Nummerering" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3301,21 +3302,21 @@ msgstr "Nummerering" msgid "Role" msgstr "Rolle" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Serienummer" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Aktivemærke" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3325,7 +3326,7 @@ msgstr "Aktivemærke" msgid "Airflow" msgstr "Luftstrøm" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3345,7 +3346,7 @@ msgstr "Luftstrøm" msgid "Rack" msgstr "Rack" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3354,49 +3355,49 @@ msgstr "Rack" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Standardplatform" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Varenummer" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "U højde" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Ekskluder fra udnyttelse" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Enhedstype" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Modultype" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Chassis" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VM-rolle" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3409,19 +3410,19 @@ msgstr "VM-rolle" msgid "Config template" msgstr "Konfigurationsskabelon" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Enhedstype" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Enhedsrolle" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3435,8 +3436,28 @@ msgstr "Enhedsrolle" msgid "Platform" msgstr "Platformen" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Klynge" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3493,22 +3514,27 @@ msgstr "Platformen" msgid "Device" msgstr "Enhed" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Konfiguration" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualisering" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Modultype" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3520,82 +3546,82 @@ msgstr "Modultype" msgid "Label" msgstr "Mærke" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Længde" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Længdeenhed" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "domæne" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Strømpanel" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Forsyning" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Spænding" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Strømstyrke" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Maksimal udnyttelse" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maksimal trækning" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maksimal forbrug (watt)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Tildelt lodtrækning" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Allokeret forbrug (watt)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Strømstik" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Foderben" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Kun ledelse" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3603,7 +3629,7 @@ msgstr "Kun ledelse" msgid "PoE mode" msgstr "PoE-tilstand" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3611,12 +3637,12 @@ msgstr "PoE-tilstand" msgid "PoE type" msgstr "PoE-type" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Trådløs rolle" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3626,16 +3652,16 @@ msgstr "Trådløs rolle" msgid "Module" msgstr "Modul" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "FORSINKELSE" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Virtuelle enhedskontekster" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3644,7 +3670,7 @@ msgstr "Virtuelle enhedskontekster" msgid "Speed" msgstr "Hastighed" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3655,36 +3681,44 @@ msgstr "Hastighed" msgid "Mode" msgstr "Tilstand" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN-gruppe" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "Umærket VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Mærkede VLAN'er" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Trådløs LAN-gruppe" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Trådløse LAN" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3692,33 +3726,37 @@ msgstr "Trådløse LAN" msgid "Addressing" msgstr "Adressering" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Betjening" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Relaterede grænseflader" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q-skift" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Interfacetilstand skal specificeres for at tildele VLAN'er" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "En adgangsgrænseflade kan ikke have tildelt taggede VLAN'er." @@ -3859,26 +3897,6 @@ msgstr "Tildelt platform" msgid "Virtual chassis" msgstr "Virtuelt kabinet" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Klynge" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Virtualiseringsklynge" @@ -6570,31 +6588,31 @@ msgstr "Der opstod en fejl under gengivelse af skabelonen: {error}" msgid "Virtual Machines" msgstr "Virtuelle maskiner" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Installeret enhed {device} i bugten {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Fjernet enhed {device} fra bugten {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Børn" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Tilføjet medlem {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Kan ikke fjerne masterenheden {device} fra det virtuelle chassis." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Fjernet {device} fra virtuelt chassis {chassis}" @@ -7529,19 +7547,19 @@ msgstr "Planlæg udførelse af script til et bestemt tidspunkt" msgid "Interval at which this script is re-run (in minutes)" msgstr "Interval, hvor scriptet køres igen (i minutter)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Databaseændringer er blevet tilbageført automatisk." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Script afbrudt med fejl: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Der opstod en undtagelse: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Databaseændringer er blevet tilbageført på grund af fejl." @@ -8853,7 +8871,7 @@ msgstr "VLAN-gruppen" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9108,7 +9126,7 @@ msgstr "Tildelt til en grænseflade" msgid "DNS Name" msgstr "DNS-navn" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9118,7 +9136,7 @@ msgstr "VLAN'er" msgid "Contains VLAN ID" msgstr "Indeholder VLAN ID" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN-ID" @@ -9575,40 +9593,48 @@ msgstr "Kan ikke indstille scope_type uden scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Kan ikke indstille scope_id uden scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Intervaller kan ikke overlappe hinanden." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Maksimal børneVID skal være større end eller lig med minimum børns VID " -"({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Det specifikke område, som dette VLAN er tildelt (hvis nogen)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN-gruppe (valgfrit)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Numerisk VLAN-id (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Driftsstatus for dette VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Den primære funktion af denne VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9617,7 +9643,7 @@ msgstr "" "VLAN er tildelt til gruppe {group} (anvendelsesområde: {scope}); kan ikke " "også tildele til området {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10361,10 +10387,6 @@ msgstr "IPsec-politikker" msgid "IPSec Profiles" msgstr "IPsec-profiler" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualisering" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10769,19 +10791,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Række {i}: Objekt med ID {id} findes ikke" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Nej {object_type} blev udvalgt." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Omdøbt {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Slettet {count} {object_type}" @@ -10813,7 +10835,7 @@ msgstr "Synkroniseret {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} skal implementere get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12671,7 +12693,7 @@ msgid "You do not have permission to run scripts" msgstr "Du har ikke tilladelse til at køre scripts" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Kør script" @@ -12683,27 +12705,32 @@ msgstr "Fejl ved indlæsning af script" msgid "Script no longer exists in the source file." msgstr "Script findes ikke længere i kildefilen." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Sidste løb" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Script findes ikke længere i kildefilen" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Aldrig" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Kør igen" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Ingen scripts fundet" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14546,13 +14573,13 @@ msgid "Memory (MB)" msgstr "Hukommelse (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disk (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Størrelse (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/de/LC_MESSAGES/django.mo b/netbox/translations/de/LC_MESSAGES/django.mo index fdcad7156..846596620 100644 Binary files a/netbox/translations/de/LC_MESSAGES/django.mo and b/netbox/translations/de/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/de/LC_MESSAGES/django.po b/netbox/translations/de/LC_MESSAGES/django.po index e2964dc56..ed56b2276 100644 --- a/netbox/translations/de/LC_MESSAGES/django.po +++ b/netbox/translations/de/LC_MESSAGES/django.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: chbally, 2024\n" "Language-Team: German (https://app.transifex.com/netbox-community/teams/178115/de/)\n" @@ -90,8 +90,8 @@ msgid "Your password has been changed successfully." msgstr "Dein Passwort wurde erfolgreich geändert." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Geplant" @@ -102,7 +102,7 @@ msgstr "Provisionierung" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -112,7 +112,7 @@ msgid "Active" msgstr "Aktiv" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Offline" @@ -125,7 +125,7 @@ msgstr "Deprovisionierung" msgid "Decommissioned" msgstr "Stillgelegt" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primär" @@ -184,8 +184,8 @@ msgstr "Standortgruppe (URL-Slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -350,7 +350,7 @@ msgstr "Transportnetzgruppe (SLUG)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -362,21 +362,21 @@ msgstr "ASNs" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -417,7 +417,7 @@ msgstr "ASNs" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -484,9 +484,9 @@ msgid "Service ID" msgstr "Dienst ID" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -503,11 +503,11 @@ msgstr "Farbe" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -552,11 +552,11 @@ msgstr "Providerkonto" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -583,7 +583,7 @@ msgstr "Providerkonto" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -608,10 +608,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -715,11 +715,11 @@ msgstr "Portgeschwindigkeit (Kbit/s)" msgid "Upstream speed (Kbps)" msgstr "Upstream Geschwindigkeit (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Als verbunden markieren" @@ -797,9 +797,9 @@ msgid "Provider network" msgstr "Providernetzwerk" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -846,8 +846,8 @@ msgid "Contacts" msgstr "Kontakte" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -870,7 +870,7 @@ msgid "Region" msgstr "Region" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -888,7 +888,7 @@ msgstr "Standortgruppe" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -923,16 +923,17 @@ msgstr "Konto" msgid "Term Side" msgstr "Terminationsseite" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Zuweisung" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -998,7 +999,7 @@ msgstr "Eindeutige Transportnetz-ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1138,7 +1139,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1249,7 +1250,7 @@ msgstr "Providernetzwerke" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1387,7 +1388,7 @@ msgstr "Abgeschlossen" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Fehlgeschlagen" @@ -1534,8 +1535,8 @@ msgid "User name" msgstr "Benutzername" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1635,7 +1636,7 @@ msgid "Completed before" msgstr "Abgeschlossen vor" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1698,9 +1699,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Rackübersichten" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Stromversorgung" @@ -2237,11 +2238,11 @@ msgstr "Job {id}wurde gestoppt" msgid "Failed to stop job {id}" msgstr "Fehler beim Stoppen des Job {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Der Plugin-Katalog konnte nicht geladen werden" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} nicht gefunden" @@ -2259,7 +2260,7 @@ msgid "Staging" msgstr "Bereitstellung" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Außerbetriebnahme" @@ -2319,7 +2320,7 @@ msgstr "Veraltet" msgid "Millimeters" msgstr "Millimeter" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Zoll" @@ -2331,8 +2332,8 @@ msgstr "Front- zu Rückseite" msgid "Rear to front" msgstr "Rück- zu Frontseite" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2406,7 +2407,7 @@ msgstr "Von unten nach oben" msgid "Top to bottom" msgstr "Von oben nach unten" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passiv" @@ -2434,8 +2435,8 @@ msgstr "International/ITA" msgid "Proprietary" msgstr "Propritär" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Andere" @@ -2448,22 +2449,22 @@ msgstr "ITA/International" msgid "Physical" msgstr "Physikalisch" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtuell" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Funknetze" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Virtuelle Schnittstellen" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2473,155 +2474,155 @@ msgstr "Virtuelle Schnittstellen" msgid "Bridge" msgstr "Bridge" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Link Aggregation Group (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fest)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modular)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (Backplane)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Mobilfunk" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Seriell" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Koaxial" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Stapelnd" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Halb" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Voll" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Automatisch" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Untagged" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Tagged" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Tagged (Alle)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE-Standard" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Passiv 24 V (2 Paare)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Passiv 24 V (4 Paare)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Passiv 48 V (2 Paare)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Passiv 48 V (4 Paare)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Kupfer" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Glasfaser" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Faser" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Verbunden" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometer" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Meter" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Zentimeter" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Meilen" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Fuß" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogramm" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramm" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Pfund" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Unzen" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundant" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Einphasig" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Dreiphasig" @@ -2854,7 +2855,7 @@ msgstr "Clustergruppe (ID)" msgid "Device model (slug)" msgstr "Gerätemodell (URL-Slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Hat volle Tiefe" @@ -2970,7 +2971,7 @@ msgstr "Zugewiesenes VLAN" msgid "Assigned VID" msgstr "Zugewiesene VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3131,27 +3132,27 @@ msgstr "" "Alphanumerische Bereiche werden unterstützt. (Muss der Anzahl der Namen " "entsprechen, die erstellt werden.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Name des Kontakts" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Telefon des Kontakts" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "E-Mail des Kontakts" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Zeitzone" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3174,51 +3175,51 @@ msgstr "Zeitzone" msgid "Manufacturer" msgstr "Hersteller" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Formfaktor" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Breite" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Höhe (HE)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Absteigende Höheneinheiten (HE)" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Äußere Breite" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Äußere Tiefe" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Äußere Einheit" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Einbautiefe" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3239,13 +3240,13 @@ msgstr "Einbautiefe" msgid "Weight" msgstr "Gewicht" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Maximales Gewicht" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3253,31 +3254,31 @@ msgstr "Maximales Gewicht" msgid "Weight unit" msgstr "Gewichtseinheit" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Rack-Typ" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Äußere Abmessungen" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Abmessungen" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Nummerierung" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3317,21 +3318,21 @@ msgstr "Nummerierung" msgid "Role" msgstr "Rolle" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Seriennummer" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Asset-Tag" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3341,7 +3342,7 @@ msgstr "Asset-Tag" msgid "Airflow" msgstr "Luftstrom" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3361,7 +3362,7 @@ msgstr "Luftstrom" msgid "Rack" msgstr "Rack" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3370,49 +3371,49 @@ msgstr "Rack" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Standard-Betriebssystem" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Artikelnummer" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Höheneinheit" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Von der Nutzung ausschließen" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Gerätetyp" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Modultyp" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Gehäuse" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VM-Rolle" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3425,19 +3426,19 @@ msgstr "VM-Rolle" msgid "Config template" msgstr "Konfigurationsvorlage" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Gerätetyp" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Geräterolle" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3451,8 +3452,28 @@ msgstr "Geräterolle" msgid "Platform" msgstr "Betriebssystem" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Cluster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3509,22 +3530,27 @@ msgstr "Betriebssystem" msgid "Device" msgstr "Gerät" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Konfiguration" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualisierung" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Modultyp" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3536,82 +3562,82 @@ msgstr "Modultyp" msgid "Label" msgstr "Label" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Länge" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Längeneinheit" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Domäne" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Stromverteiler" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Versorgung" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Phase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Spannung" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Stromstärke" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Max. Auslastung" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maximale Auslastung" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maximale Leistungsaufnahme (Watt)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Zugewiesene Leistungsaufnahme" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Zugewiesene Leistungsaufnahme (Watt)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Stromanschluss" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Phasenlage" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Nur Management" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3619,7 +3645,7 @@ msgstr "Nur Management" msgid "PoE mode" msgstr "PoE-Modus" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3627,12 +3653,12 @@ msgstr "PoE-Modus" msgid "PoE type" msgstr "PoE-Typ" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "WLAN Funktion" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3642,16 +3668,16 @@ msgstr "WLAN Funktion" msgid "Module" msgstr "Modul" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Virtual Device Contexts" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3660,7 +3686,7 @@ msgstr "Virtual Device Contexts" msgid "Speed" msgstr "Geschwindigkeit" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3671,36 +3697,44 @@ msgstr "Geschwindigkeit" msgid "Mode" msgstr "Modus" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN-Gruppe" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "Untagged VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Getaggte VLANs" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "Hinzufügen eines getaggten VLANs" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "Getaggte VLANs entfernen" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "WLAN-Gruppe" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "WLANs" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3708,33 +3742,37 @@ msgstr "WLANs" msgid "Addressing" msgstr "Adressierung" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Dienst / Port" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Verwandte Schnittstellen" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q-Switching" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "Hinzufügen/Entfernen" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Der Schnittstellenmodus muss gesetzt werden, um VLANs zuzuweisen" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "" "Einer Endgeräteschnittstelle (Access) können keine getaggten VLANs " @@ -3877,26 +3915,6 @@ msgstr "Zugewiesenes Betriebssystem" msgid "Virtual chassis" msgstr "Virtuelles Gehäuse" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Cluster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Virtualisierungscluster" @@ -6670,33 +6688,33 @@ msgstr "Ein Fehler ist beim Rendern der Vorlage aufgetreten: {error}" msgid "Virtual Machines" msgstr "Virtuelle Maschinen" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Gerät {device} im Schacht {device_bay} installiert." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Gerät {device} im Schacht {device_bay} entfernt." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Untergeordnet" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Mitglied hinzugefügt {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "Ein Hauptgerät (Master Device) {device} kann von einem virtuellen Gehäuse " "nicht entfernt werden." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "{device} vom virtuellen Gehäuse {chassis} entfernt." @@ -7657,19 +7675,19 @@ msgstr "Planen Sie die Ausführung des Skripts auf eine festgelegte Zeit" msgid "Interval at which this script is re-run (in minutes)" msgstr "Intervall, in dem dieses Skript erneut ausgeführt wird (in Minuten)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Datenbankänderungen wurden automatisch rückgängig gemacht." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Das Skript wurde mit einem Fehler abgebrochen: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Eine Ausnahme ist aufgetreten: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Datenbankänderungen wurden aufgrund eines Fehlers rückgängig gemacht." @@ -9010,7 +9028,7 @@ msgstr "VLAN-Gruppe" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9267,7 +9285,7 @@ msgstr "Einer Schnittstelle zugewiesen" msgid "DNS Name" msgstr "DNS-Name" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9277,7 +9295,7 @@ msgstr "VLANs" msgid "Contains VLAN ID" msgstr "Enthält VLAN-ID" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN-ID" @@ -9746,41 +9764,49 @@ msgstr "scope_type kann nicht ohne scope_id gesetzt werden." msgid "Cannot set scope_id without scope_type." msgstr "scope_id kann nicht ohne scope_type gesetzt werden." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Bereiche dürfen sich nicht überschneiden." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Die maximale untergeordnete VID muss größer oder gleich der Mindest-VID für " -"untergeordnete VIDs sein ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "" "Der spezifische Standort, der dieses VLAN zugewiesen ist (falls vorhanden)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN-Gruppe (optional)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Numerische VLAN-ID (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Betriebsstatus dieses VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Die Hauptfunktion dieses VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9789,7 +9815,7 @@ msgstr "" "VLAN ist der Gruppe {group} (Scope: {scope}) zugewiesen; kann nicht auch dem" " Standort {site} zugewiesen werden." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10537,10 +10563,6 @@ msgstr "IPSec-Richtlinien" msgid "IPSec Profiles" msgstr "IPSec-Profile" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualisierung" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10951,19 +10973,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Reihe {i}: Objekt mit ID {id} existiert nicht" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Kein {object_type}ausgewählt" -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Umbenannt {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Gelöscht {count} {object_type}" @@ -10995,7 +11017,7 @@ msgstr "Synchronisiert {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} muss get_children () implementieren" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12859,7 +12881,7 @@ msgid "You do not have permission to run scripts" msgstr "Sie sind nicht berechtigt, Skripts auszuführen" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Skript ausführen" @@ -12871,27 +12893,32 @@ msgstr "Fehler beim Laden des Skripts" msgid "Script no longer exists in the source file." msgstr "Das Skript ist in der Quelldatei nicht mehr vorhanden." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Letzter Lauf" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Das Skript ist in der Quelldatei nicht mehr vorhanden" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Niemals" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Nochmal ausführen" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "Skripte konnten nicht aus dem Modul geladen werden %(module)s" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Keine Skripte gefunden" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14759,13 +14786,13 @@ msgid "Memory (MB)" msgstr "Speicher (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Festplatte (GB)" +msgid "Disk (MB)" +msgstr "Festplatte (MB)" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Größe (GB)" +msgid "Size (MB)" +msgstr "Größe (MB)" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/en/LC_MESSAGES/django.po b/netbox/translations/en/LC_MESSAGES/django.po index 7692853f4..7944e0a33 100644 --- a/netbox/translations/en/LC_MESSAGES/django.po +++ b/netbox/translations/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-29 21:00+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -78,8 +78,8 @@ msgid "Your password has been changed successfully." msgstr "" #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "" @@ -90,7 +90,7 @@ msgstr "" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 ipam/choices.py:154 #: templates/extras/configcontext.html:25 templates/users/user.html:37 #: users/forms/bulk_edit.py:38 virtualization/choices.py:22 @@ -99,7 +99,7 @@ msgid "Active" msgstr "" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "" @@ -112,7 +112,7 @@ msgstr "" msgid "Decommissioned" msgstr "" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "" @@ -171,8 +171,8 @@ msgstr "" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -332,7 +332,7 @@ msgstr "" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -344,21 +344,21 @@ msgstr "" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -398,7 +398,7 @@ msgstr "" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -464,9 +464,9 @@ msgid "Service ID" msgstr "" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -483,11 +483,11 @@ msgstr "" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -532,11 +532,11 @@ msgstr "" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -562,7 +562,7 @@ msgstr "" #: templates/dcim/cable.html:19 templates/dcim/device.html:178 #: templates/dcim/location.html:45 templates/dcim/module.html:69 #: templates/dcim/powerfeed.html:36 templates/dcim/rack.html:41 -#: templates/dcim/site.html:43 templates/extras/script_list.html:47 +#: templates/dcim/site.html:43 templates/extras/script_list.html:48 #: templates/ipam/ipaddress.html:37 templates/ipam/iprange.html:54 #: templates/ipam/prefix.html:73 templates/ipam/vlan.html:48 #: templates/virtualization/cluster.html:21 @@ -586,10 +586,10 @@ msgstr "" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -692,11 +692,11 @@ msgstr "" msgid "Upstream speed (Kbps)" msgstr "" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "" @@ -774,9 +774,9 @@ msgid "Provider network" msgstr "" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -821,8 +821,8 @@ msgid "Contacts" msgstr "" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -844,7 +844,7 @@ msgid "Region" msgstr "" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -862,7 +862,7 @@ msgstr "" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -897,16 +897,17 @@ msgstr "" msgid "Term Side" msgstr "" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -972,7 +973,7 @@ msgstr "" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1106,7 +1107,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1215,7 +1216,7 @@ msgstr "" #: templates/extras/customlink.html:13 templates/extras/eventrule.html:13 #: templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1351,7 +1352,7 @@ msgstr "" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "" @@ -1498,8 +1499,8 @@ msgid "User name" msgstr "" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1598,7 +1599,7 @@ msgid "Completed before" msgstr "" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1658,9 +1659,9 @@ msgstr "" msgid "Rack Elevations" msgstr "" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "" @@ -2184,11 +2185,11 @@ msgstr "" msgid "Failed to stop job {id}" msgstr "" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "" @@ -2206,7 +2207,7 @@ msgid "Staging" msgstr "" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "" @@ -2266,7 +2267,7 @@ msgstr "" msgid "Millimeters" msgstr "" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "" @@ -2278,8 +2279,8 @@ msgstr "" msgid "Rear to front" msgstr "" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2353,7 +2354,7 @@ msgstr "" msgid "Top to bottom" msgstr "" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "" @@ -2381,8 +2382,8 @@ msgstr "" msgid "Proprietary" msgstr "" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "" @@ -2395,22 +2396,22 @@ msgstr "" msgid "Physical" msgstr "" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2420,155 +2421,155 @@ msgstr "" msgid "Bridge" msgstr "" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "" @@ -2801,7 +2802,7 @@ msgstr "" msgid "Device model (slug)" msgstr "" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "" @@ -2917,7 +2918,7 @@ msgstr "" msgid "Assigned VID" msgstr "" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3076,27 +3077,27 @@ msgid "" "created.)" msgstr "" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3119,51 +3120,51 @@ msgstr "" msgid "Manufacturer" msgstr "" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3184,13 +3185,13 @@ msgstr "" msgid "Weight" msgstr "" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3198,31 +3199,31 @@ msgstr "" msgid "Weight unit" msgstr "" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3262,21 +3263,21 @@ msgstr "" msgid "Role" msgstr "" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3286,7 +3287,7 @@ msgstr "" msgid "Airflow" msgstr "" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3306,7 +3307,7 @@ msgstr "" msgid "Rack" msgstr "" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3315,49 +3316,49 @@ msgstr "" msgid "Hardware" msgstr "" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3370,19 +3371,19 @@ msgstr "" msgid "Config template" msgstr "" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3396,8 +3397,26 @@ msgstr "" msgid "Platform" msgstr "" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3454,22 +3473,27 @@ msgstr "" msgid "Device" msgstr "" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3481,101 +3505,101 @@ msgstr "" msgid "Label" msgstr "" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 dcim/models/device_component_templates.py:437 #: dcim/models/device_components.py:670 msgid "PoE mode" msgstr "" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 dcim/models/device_component_templates.py:443 #: dcim/models/device_components.py:676 msgid "PoE type" msgstr "" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3585,16 +3609,16 @@ msgstr "" msgid "Module" msgstr "" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3603,7 +3627,7 @@ msgstr "" msgid "Speed" msgstr "" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3614,36 +3638,44 @@ msgstr "" msgid "Mode" msgstr "" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3651,33 +3683,37 @@ msgstr "" msgid "Addressing" msgstr "" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "" @@ -3818,24 +3854,6 @@ msgstr "" msgid "Virtual chassis" msgstr "" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "" @@ -6423,31 +6441,31 @@ msgstr "" msgid "Virtual Machines" msgstr "" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "" -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "" -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "" @@ -7363,19 +7381,19 @@ msgstr "" msgid "Interval at which this script is re-run (in minutes)" msgstr "" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "" -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "" -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "" -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "" @@ -8629,7 +8647,7 @@ msgstr "" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 templates/ipam/prefix.html:60 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 templates/ipam/prefix.html:60 #: templates/ipam/vlan.html:12 templates/ipam/vlan/base.html:6 #: templates/ipam/vlan_edit.html:10 templates/wireless/wirelesslan.html:30 #: vpn/forms/bulk_import.py:304 vpn/forms/filtersets.py:284 @@ -8882,7 +8900,7 @@ msgstr "" msgid "DNS Name" msgstr "" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -8892,7 +8910,7 @@ msgstr "" msgid "Contains VLAN ID" msgstr "" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "" @@ -9328,45 +9346,55 @@ msgstr "" msgid "Cannot set scope_id without scope_type." msgstr "" -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "" -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " "site {site}." msgstr "" -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10099,10 +10127,6 @@ msgstr "" msgid "IPSec Profiles" msgstr "" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10498,19 +10522,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "" -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "" @@ -10542,7 +10566,7 @@ msgstr "" msgid "{class_name} must implement get_children()" msgstr "" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12359,7 +12383,7 @@ msgid "You do not have permission to run scripts" msgstr "" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "" @@ -12371,27 +12395,32 @@ msgstr "" msgid "Script no longer exists in the source file." msgstr "" -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "" -#: templates/extras/script_list.html:138 -msgid "No Scripts Found" +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" msgstr "" #: templates/extras/script_list.html:141 +msgid "No Scripts Found" +msgstr "" + +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14145,11 +14174,11 @@ msgid "Memory (MB)" msgstr "" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" +msgid "Disk (MB)" msgstr "" #: virtualization/forms/bulk_edit.py:334 virtualization/forms/filtersets.py:251 -msgid "Size (GB)" +msgid "Size (MB)" msgstr "" #: virtualization/forms/bulk_import.py:44 diff --git a/netbox/translations/es/LC_MESSAGES/django.mo b/netbox/translations/es/LC_MESSAGES/django.mo index 86fb45730..5c7e126e0 100644 Binary files a/netbox/translations/es/LC_MESSAGES/django.mo and b/netbox/translations/es/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/es/LC_MESSAGES/django.po b/netbox/translations/es/LC_MESSAGES/django.po index ee77d76fc..480eb9f0f 100644 --- a/netbox/translations/es/LC_MESSAGES/django.po +++ b/netbox/translations/es/LC_MESSAGES/django.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Spanish (https://app.transifex.com/netbox-community/teams/178115/es/)\n" @@ -84,8 +84,8 @@ msgid "Your password has been changed successfully." msgstr "La contraseña se ha cambiado correctamente." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planificado" @@ -96,7 +96,7 @@ msgstr "Aprovisionamiento" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -106,7 +106,7 @@ msgid "Active" msgstr "Activo" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Desconectado" @@ -119,7 +119,7 @@ msgstr "Desaprovisionamiento" msgid "Decommissioned" msgstr "Desmantelado" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primaria" @@ -178,8 +178,8 @@ msgstr "Grupo de sitios (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -344,7 +344,7 @@ msgstr "Grupo de circuitos (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -356,21 +356,21 @@ msgstr "ASNs" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -411,7 +411,7 @@ msgstr "ASNs" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -478,9 +478,9 @@ msgid "Service ID" msgstr "ID de servicio" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -497,11 +497,11 @@ msgstr "Color" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -546,11 +546,11 @@ msgstr "Cuenta de proveedor" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -577,7 +577,7 @@ msgstr "Cuenta de proveedor" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -602,10 +602,10 @@ msgstr "Estado" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -709,11 +709,11 @@ msgstr "Velocidad del puerto (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Velocidad de subida (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Marcar conectado" @@ -791,9 +791,9 @@ msgid "Provider network" msgstr "Red de proveedores" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -840,8 +840,8 @@ msgid "Contacts" msgstr "Contactos" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -864,7 +864,7 @@ msgid "Region" msgstr "Región" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -882,7 +882,7 @@ msgstr "Grupo de sitios" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -917,16 +917,17 @@ msgstr "Cuenta" msgid "Term Side" msgstr "Lado del término" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Asignación" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -992,7 +993,7 @@ msgstr "ID de circuito único" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1131,7 +1132,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1242,7 +1243,7 @@ msgstr "redes de proveedores" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1379,7 +1380,7 @@ msgstr "Completado" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Falló" @@ -1526,8 +1527,8 @@ msgid "User name" msgstr "Nombre de usuario" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1627,7 +1628,7 @@ msgid "Completed before" msgstr "Completado antes" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1689,9 +1690,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Elevaciones de estanterías" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Potencia" @@ -2227,11 +2228,11 @@ msgstr "Trabajo {id} se ha detenido." msgid "Failed to stop job {id}" msgstr "No se pudo detener el trabajo {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "No se pudo cargar el catálogo de complementos" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} no se encontró" @@ -2249,7 +2250,7 @@ msgid "Staging" msgstr "Puesta en escena" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Desmantelamiento" @@ -2309,7 +2310,7 @@ msgstr "Obsoleto" msgid "Millimeters" msgstr "Milímetros" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Pulgadas" @@ -2321,8 +2322,8 @@ msgstr "De adelante hacia atrás" msgid "Rear to front" msgstr "De atrás hacia adelante" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2396,7 +2397,7 @@ msgstr "De abajo hacia arriba" msgid "Top to bottom" msgstr "De arriba a abajo" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Pasivo" @@ -2424,8 +2425,8 @@ msgstr "Internacional/ITA" msgid "Proprietary" msgstr "Proprietario" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Otros" @@ -2438,22 +2439,22 @@ msgstr "ITA/Internacional" msgid "Physical" msgstr "Físico" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtual" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "inalámbrico" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Interfaces virtuales" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2463,155 +2464,155 @@ msgstr "Interfaces virtuales" msgid "Bridge" msgstr "puente" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Grupo de agregación de enlaces (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fijo)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modular)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (placa base)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Celular" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "serie" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Coaxial" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Apilamiento" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Mitad" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Lleno" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Auto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Acceso" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Etiquetado" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Etiquetado (Todos)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Estándar IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Pasivo 24 V (2 pares)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Pasivo de 24 V (4 pares)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Pasivo 48 V (2 pares)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Pasivo de 48 V (4 pares)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Cobre" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Fibra óptica" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fibra" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Conectado" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilómetros" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Medidores" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centímetros" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Millas" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Pies" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogramos" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramos" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Libras" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Onzas" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundante" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Monofásico" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Trifásico" @@ -2844,7 +2845,7 @@ msgstr "Grupo de clústeres (ID)" msgid "Device model (slug)" msgstr "Modelo de dispositivo (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Es de profundidad total" @@ -2960,7 +2961,7 @@ msgstr "VLAN asignada" msgid "Assigned VID" msgstr "VID asignado" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3121,27 +3122,27 @@ msgstr "" "Se admiten los rangos alfanuméricos. (Debe coincidir con el número de " "nombres que se están creando)." -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Nombre de contacto" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Teléfono de contacto" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Correo electrónico de contacto" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Zona horaria" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3164,51 +3165,51 @@ msgstr "Zona horaria" msgid "Manufacturer" msgstr "fabricante" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Factor de forma" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Anchura" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Altura (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Unidades descendentes" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Anchura exterior" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Profundidad exterior" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Unidad exterior" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Profundidad de montaje" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3229,13 +3230,13 @@ msgstr "Profundidad de montaje" msgid "Weight" msgstr "Peso" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Peso máximo" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3243,31 +3244,31 @@ msgstr "Peso máximo" msgid "Weight unit" msgstr "Unidad de peso" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Tipo de bastidor" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Dimensiones exteriores" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensiones" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numeración" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3307,21 +3308,21 @@ msgstr "Numeración" msgid "Role" msgstr "Rol" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Número de serie" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Etiqueta de activo" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3331,7 +3332,7 @@ msgstr "Etiqueta de activo" msgid "Airflow" msgstr "Flujo de aire" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3351,7 +3352,7 @@ msgstr "Flujo de aire" msgid "Rack" msgstr "Estante" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3360,49 +3361,49 @@ msgstr "Estante" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Plataforma predeterminada" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Número de pieza" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Altura en U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Excluir de la utilización" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Tipo de dispositivo" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Tipo de módulo" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Chasis" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Función de máquina virtual" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3415,19 +3416,19 @@ msgstr "Función de máquina virtual" msgid "Config template" msgstr "Plantilla de configuración" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Tipo de dispositivo" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Función del dispositivo" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3441,8 +3442,28 @@ msgstr "Función del dispositivo" msgid "Platform" msgstr "Plataforma" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Clúster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3499,22 +3520,27 @@ msgstr "Plataforma" msgid "Device" msgstr "Dispositivo" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Configuración" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualización" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Tipo de módulo" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3526,82 +3552,82 @@ msgstr "Tipo de módulo" msgid "Label" msgstr "Etiqueta" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Longitud" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Unidad de longitud" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Dominio" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Panel de alimentación" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Suministro" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Tensión" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Amperaje" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Utilización máxima" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Sorteo máximo" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Consumo máximo de energía (vatios)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Sorteo asignado" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Consumo de energía asignado (vatios)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Puerto de alimentación" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Pierna de alimentación" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Solo administración" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3609,7 +3635,7 @@ msgstr "Solo administración" msgid "PoE mode" msgstr "Modo PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3617,12 +3643,12 @@ msgstr "Modo PoE" msgid "PoE type" msgstr "Tipo de PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Función inalámbrica" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3632,16 +3658,16 @@ msgstr "Función inalámbrica" msgid "Module" msgstr "Módulo" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "DESFASE" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Contextos de dispositivos virtuales" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3650,7 +3676,7 @@ msgstr "Contextos de dispositivos virtuales" msgid "Speed" msgstr "Velocidad" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3661,36 +3687,44 @@ msgstr "Velocidad" msgid "Mode" msgstr "Modo" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Grupo de VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN sin etiquetar" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "VLAN etiquetadas" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Grupo LAN inalámbrico" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "LAN inalámbricas" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3698,33 +3732,37 @@ msgstr "LAN inalámbricas" msgid "Addressing" msgstr "Dirigiéndose" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operación" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Interfaces relacionadas" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Conmutación 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Se debe especificar el modo de interfaz para asignar las VLAN" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Una interfaz de acceso no puede tener asignadas VLAN etiquetadas." @@ -3866,26 +3904,6 @@ msgstr "Plataforma asignada" msgid "Virtual chassis" msgstr "Chasis virtual" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Clúster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Clúster de virtualización" @@ -6632,33 +6650,33 @@ msgstr "Se ha producido un error al renderizar la plantilla: {error}" msgid "Virtual Machines" msgstr "Máquinas virtuales" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Dispositivo instalado {device} en la bahía {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Dispositivo eliminado {device} desde la bahía {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Niños" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Miembro agregado {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "No se puede eliminar el dispositivo maestro {device} desde el chasis " "virtual." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Eliminado {device} desde un chasis virtual {chassis}" @@ -7608,19 +7626,19 @@ msgstr "Programe la ejecución del script a una hora determinada" msgid "Interval at which this script is re-run (in minutes)" msgstr "Intervalo en el que se vuelve a ejecutar este script (en minutos)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Los cambios en la base de datos se han revertido automáticamente." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Secuencia de comandos abortada con un error: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Se ha producido una excepción: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Los cambios en la base de datos se han revertido debido a un error." @@ -8953,7 +8971,7 @@ msgstr "Grupo VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9210,7 +9228,7 @@ msgstr "Asignado a una interfaz" msgid "DNS Name" msgstr "Nombre DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9220,7 +9238,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "Contiene el identificador de VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "IDENTIFICADOR DE VLAN" @@ -9682,40 +9700,48 @@ msgstr "No se puede establecer scope_type sin scope_id." msgid "Cannot set scope_id without scope_type." msgstr "No se puede establecer scope_id sin scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Los rangos no se pueden superponer." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"El VID infantil máximo debe ser mayor o igual al VID infantil mínimo " -"({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "El sitio específico al que está asignada esta VLAN (si existe)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Grupo de VLAN (opcional)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "ID de VLAN numérico (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Estado operativo de esta VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "La función principal de esta VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9724,7 +9750,7 @@ msgstr "" "La VLAN está asignada al grupo {group} (alcance: {scope}); no se puede " "asignar también al sitio {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "El VID debe estar en rangos {ranges} para VLAN en grupo {group}" @@ -10477,10 +10503,6 @@ msgstr "Políticas IPSec" msgid "IPSec Profiles" msgstr "Perfiles IPSec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualización" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10885,19 +10907,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Fila {i}: Objeto con ID {id} no existe" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "No {object_type} fueron seleccionados." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Renombrado {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Eliminado {count} {object_type}" @@ -10931,7 +10953,7 @@ msgstr "Sincronizado {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} debe implementar get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12795,7 +12817,7 @@ msgid "You do not have permission to run scripts" msgstr "No tiene permiso para ejecutar scripts" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Ejecutar script" @@ -12807,27 +12829,32 @@ msgstr "Error al cargar el script" msgid "Script no longer exists in the source file." msgstr "El script ya no existe en el archivo fuente." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Última ejecución" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "La secuencia de comandos ya no está presente en el archivo fuente" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Nunca" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Corre otra vez" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "No se encontró ningún script" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14690,13 +14717,13 @@ msgid "Memory (MB)" msgstr "Memoria (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disco (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Tamaño (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/fr/LC_MESSAGES/django.mo b/netbox/translations/fr/LC_MESSAGES/django.mo index bf80d8fca..4e3ff8a09 100644 Binary files a/netbox/translations/fr/LC_MESSAGES/django.mo and b/netbox/translations/fr/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/fr/LC_MESSAGES/django.po b/netbox/translations/fr/LC_MESSAGES/django.po index a01027e68..0f413867e 100644 --- a/netbox/translations/fr/LC_MESSAGES/django.po +++ b/netbox/translations/fr/LC_MESSAGES/django.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: French (https://app.transifex.com/netbox-community/teams/178115/fr/)\n" @@ -91,8 +91,8 @@ msgid "Your password has been changed successfully." msgstr "Votre mot de passe a été modifié avec succès." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planifié" @@ -103,7 +103,7 @@ msgstr "Approvisionnement" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -113,7 +113,7 @@ msgid "Active" msgstr "Actif" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Hors ligne" @@ -126,7 +126,7 @@ msgstr "Déprovisionnement" msgid "Decommissioned" msgstr "Mis hors service" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primaire" @@ -185,8 +185,8 @@ msgstr "Groupe de sites (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -351,7 +351,7 @@ msgstr "Groupe de circuits (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -363,21 +363,21 @@ msgstr "Numéros d'AS" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -418,7 +418,7 @@ msgstr "Numéros d'AS" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -485,9 +485,9 @@ msgid "Service ID" msgstr "Identifiant du service" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -504,11 +504,11 @@ msgstr "Couleur" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -553,11 +553,11 @@ msgstr "Identifiant de compte du prestataire" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -584,7 +584,7 @@ msgstr "Identifiant de compte du prestataire" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -609,10 +609,10 @@ msgstr "Statut" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -716,11 +716,11 @@ msgstr "Vitesse du port (Kbits/s)" msgid "Upstream speed (Kbps)" msgstr "Vitesse ascendante (Kbits/s)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Marquer comme connecté" @@ -798,9 +798,9 @@ msgid "Provider network" msgstr "Réseau de fournisseurs" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -847,8 +847,8 @@ msgid "Contacts" msgstr "Contacts" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -871,7 +871,7 @@ msgid "Region" msgstr "Région" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -889,7 +889,7 @@ msgstr "Groupe de sites" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -924,16 +924,17 @@ msgstr "Compte" msgid "Term Side" msgstr "Côté terme" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Affectation" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -999,7 +1000,7 @@ msgstr "ID de circuit unique" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1138,7 +1139,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1249,7 +1250,7 @@ msgstr "réseaux de fournisseurs" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1387,7 +1388,7 @@ msgstr "Terminé" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Échoué" @@ -1534,8 +1535,8 @@ msgid "User name" msgstr "Nom d'utilisateur" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1635,7 +1636,7 @@ msgid "Completed before" msgstr "Terminé avant" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1699,9 +1700,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Élévations des baies" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Puissance" @@ -2240,11 +2241,11 @@ msgstr "Poste {id} a été arrêté." msgid "Failed to stop job {id}" msgstr "Impossible d'arrêter la tâche {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Le catalogue des plugins n'a pas pu être chargé" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plug-in {name} introuvable" @@ -2262,7 +2263,7 @@ msgid "Staging" msgstr "Mise en scène" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Démantèlement" @@ -2322,7 +2323,7 @@ msgstr "Obsolète" msgid "Millimeters" msgstr "Millimètres" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Pouces" @@ -2334,8 +2335,8 @@ msgstr "De l'avant vers l'arrière" msgid "Rear to front" msgstr "De l'arrière vers l'avant" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2409,7 +2410,7 @@ msgstr "De bas en haut" msgid "Top to bottom" msgstr "De haut en bas" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passif" @@ -2437,8 +2438,8 @@ msgstr "International/ITA" msgid "Proprietary" msgstr "Propriétaire" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Autres" @@ -2451,22 +2452,22 @@ msgstr "ITA/International" msgid "Physical" msgstr "Physique" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtuel" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Sans fil" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Interfaces virtuelles" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2476,155 +2477,155 @@ msgstr "Interfaces virtuelles" msgid "Bridge" msgstr "Passerelle" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Groupe d'agrégation de liens (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fixe)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modulaire)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (panneau arrière)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Cellulaire" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Série" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Coaxiale" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Empilage" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "La moitié" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Complet" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Automatique" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Accès" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Tagué" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Tagué (Tous)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Norme IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "24 V passif (2 paires)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "24 V passif (4 paires)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "48 V passif (2 paires)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "48 V passif (4 paires)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Cuivre" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "fibre optique" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fibre" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Connecté" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilomètres" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Compteurs" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centimètres" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Miles" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Pieds" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogrammes" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Grammes" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Livres" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Onces" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redondant" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Monophasé" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Triphasé" @@ -2857,7 +2858,7 @@ msgstr "Groupe de clusters (ID)" msgid "Device model (slug)" msgstr "Modèle d'appareil (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Est en pleine profondeur" @@ -2973,7 +2974,7 @@ msgstr "VLAN attribué" msgid "Assigned VID" msgstr "VID attribué" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3134,27 +3135,27 @@ msgstr "" "Les plages alphanumériques sont prises en charge. (Doit correspondre au " "nombre de noms en cours de création.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Nom du contact" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Téléphone de contact" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Adresse électronique de contact" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Fuseau horaire" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3177,51 +3178,51 @@ msgstr "Fuseau horaire" msgid "Manufacturer" msgstr "Fabricant" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Facteur de forme" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Largeur" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Hauteur (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Unités décroissantes" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Largeur extérieure" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Profondeur extérieure" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Unité extérieure" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Profondeur de montage" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3242,13 +3243,13 @@ msgstr "Profondeur de montage" msgid "Weight" msgstr "Poids" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Poids maximum" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3256,31 +3257,31 @@ msgstr "Poids maximum" msgid "Weight unit" msgstr "Unité de poids" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Type de rack" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Dimensions extérieures" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensions" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numérotation" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3320,21 +3321,21 @@ msgstr "Numérotation" msgid "Role" msgstr "Rôle" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Numéro de série" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Étiquette d'actif" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3344,7 +3345,7 @@ msgstr "Étiquette d'actif" msgid "Airflow" msgstr "Débit d'air" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3364,7 +3365,7 @@ msgstr "Débit d'air" msgid "Rack" msgstr "Baie" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3373,49 +3374,49 @@ msgstr "Baie" msgid "Hardware" msgstr "Matériel" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Plateforme par défaut" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Numéro de pièce" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Hauteur en U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Exclure de l'utilisation" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Type d'appareil" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Type de module" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Châssis" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "rôle de machine virtuelle" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3428,19 +3429,19 @@ msgstr "rôle de machine virtuelle" msgid "Config template" msgstr "Modèle de configuration" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Type d'appareil" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Rôle de l'appareil" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3454,8 +3455,28 @@ msgstr "Rôle de l'appareil" msgid "Platform" msgstr "Plateforme" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Cluster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3512,22 +3533,27 @@ msgstr "Plateforme" msgid "Device" msgstr "Appareil" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Configuration" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualisation" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Type de module" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3539,82 +3565,82 @@ msgstr "Type de module" msgid "Label" msgstr "Libellé" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Longueur" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Unité de longueur" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Domaine" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "panneau d'alimentation" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Approvisionnement" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Phase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "tension" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Ampérage" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Utilisation maximale" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Tirage maximum" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Consommation électrique maximale (watts)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Tirage au sort attribué" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Consommation électrique allouée (watts)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "port d'alimentation" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Patte d'alimentation" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Gestion uniquement" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3622,7 +3648,7 @@ msgstr "Gestion uniquement" msgid "PoE mode" msgstr "Mode PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3630,12 +3656,12 @@ msgstr "Mode PoE" msgid "PoE type" msgstr "Type PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Rôle sans fil" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3645,16 +3671,16 @@ msgstr "Rôle sans fil" msgid "Module" msgstr "Modules" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "DÉCALAGE" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Contextes des appareils virtuels" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3663,7 +3689,7 @@ msgstr "Contextes des appareils virtuels" msgid "Speed" msgstr "Vitesse" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3674,36 +3700,44 @@ msgstr "Vitesse" msgid "Mode" msgstr "Mode" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "groupe VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN non balisé" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "VLAN balisés" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Groupe LAN sans fil" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Réseaux locaux sans fil" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3711,33 +3745,37 @@ msgstr "Réseaux locaux sans fil" msgid "Addressing" msgstr "Adressage" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Fonctionnement" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Interfaces associées" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Commutation 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Le mode d'interface doit être spécifié pour attribuer des VLAN" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "" "Des tags de VLAN ne peuvent pas être associés à une interface d'accès." @@ -3879,26 +3917,6 @@ msgstr "Plateforme attribuée" msgid "Virtual chassis" msgstr "Châssis virtuel" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Cluster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Cluster de virtualisation" @@ -6640,33 +6658,33 @@ msgstr "Une erreur s'est produite lors du rendu du modèle : {error}" msgid "Virtual Machines" msgstr "Machines virtuelles" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Appareil installé {device} dans la baie {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Appareil retiré {device} depuis la baie {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Enfants" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Membre ajouté {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "Impossible de supprimer le périphérique principal {device} depuis le châssis" " virtuel." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Supprimé {device} depuis un châssis virtuel {chassis}" @@ -7620,21 +7638,21 @@ msgstr "Planifier l'exécution du script à une heure définie" msgid "Interval at which this script is re-run (in minutes)" msgstr "Intervalle auquel ce script est réexécuté (en minutes)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "" "Les modifications apportées à la base de données ont été annulées " "automatiquement." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Le script a été abandonné avec une erreur : " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Une exception s'est produite : " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "" "Les modifications apportées à la base de données ont été annulées en raison " @@ -8980,7 +8998,7 @@ msgstr "Groupe VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9238,7 +9256,7 @@ msgstr "Affecté à une interface" msgid "DNS Name" msgstr "Nom DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9248,7 +9266,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "Contient un ID de VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "IDENTIFIANT DE VLAN" @@ -9717,40 +9735,48 @@ msgstr "Impossible de définir scope_type sans scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Impossible de définir scope_id sans scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Les plages ne peuvent pas se chevaucher." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"La VID maximale pour les enfants doit être supérieure ou égale à la VID " -"minimale pour les enfants ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Le site spécifique auquel ce VLAN est associé (le cas échéant)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Groupe VLAN (facultatif)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "ID VLAN numérique (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "État opérationnel de ce VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "La principale fonction de ce VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9759,7 +9785,7 @@ msgstr "" "Le VLAN est associé au groupe {group} (champ d'application : {scope}) ; ne " "peut pas également être associé au site {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10520,10 +10546,6 @@ msgstr "Politiques IPSec" msgid "IPSec Profiles" msgstr "Profils IPSec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualisation" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10931,19 +10953,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Rangée {i}: Objet avec identifiant {id} n'existe pas" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Non {object_type} ont été sélectionnés." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Renommé {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Supprimé {count} {object_type}" @@ -10977,7 +10999,7 @@ msgstr "Synchronisé {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} doit implémenter get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12842,7 +12864,7 @@ msgid "You do not have permission to run scripts" msgstr "Vous n'avez pas le droit d'exécuter des scripts" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Exécuter le script" @@ -12854,27 +12876,32 @@ msgstr "Erreur de chargement du script" msgid "Script no longer exists in the source file." msgstr "Le script n'existe plus dans le fichier source." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Dernière exécution" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Le script n'est plus présent dans le fichier source" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Jamais" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Exécutez à nouveau" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Aucun script trouvé" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14734,13 +14761,13 @@ msgid "Memory (MB)" msgstr "Mémoire (Mo)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disque (Go)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Taille (Go)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/it/LC_MESSAGES/django.mo b/netbox/translations/it/LC_MESSAGES/django.mo index 839e15400..3e357f35d 100644 Binary files a/netbox/translations/it/LC_MESSAGES/django.mo and b/netbox/translations/it/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/it/LC_MESSAGES/django.po b/netbox/translations/it/LC_MESSAGES/django.po index af1ed0224..6020afea5 100644 --- a/netbox/translations/it/LC_MESSAGES/django.po +++ b/netbox/translations/it/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Italian (https://app.transifex.com/netbox-community/teams/178115/it/)\n" @@ -87,8 +87,8 @@ msgid "Your password has been changed successfully." msgstr "La tua password è stata cambiata con successo." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Pianificato" @@ -99,7 +99,7 @@ msgstr "Approvvigionamento" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -109,7 +109,7 @@ msgid "Active" msgstr "Attivo" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Offline" @@ -122,7 +122,7 @@ msgstr "Deprovisioning" msgid "Decommissioned" msgstr "Dismesso" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primaria" @@ -181,8 +181,8 @@ msgstr "Gruppo del sito (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -347,7 +347,7 @@ msgstr "Gruppo di circuiti (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -359,21 +359,21 @@ msgstr "ASN" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -414,7 +414,7 @@ msgstr "ASN" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -481,9 +481,9 @@ msgid "Service ID" msgstr "ID del servizio" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -500,11 +500,11 @@ msgstr "Colore" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -549,11 +549,11 @@ msgstr "Provider account " #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -580,7 +580,7 @@ msgstr "Provider account " #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -605,10 +605,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -712,11 +712,11 @@ msgstr "Port speed (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Upstream speed (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Segna connesso" @@ -794,9 +794,9 @@ msgid "Provider network" msgstr "Provider network" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -843,8 +843,8 @@ msgid "Contacts" msgstr "Contatti" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -867,7 +867,7 @@ msgid "Region" msgstr "Regione" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -885,7 +885,7 @@ msgstr "Gruppo del sito" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -920,16 +920,17 @@ msgstr "Account" msgid "Term Side" msgstr "Lato del termine" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Assegnazione" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -995,7 +996,7 @@ msgstr "ID univoco del circuito" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1134,7 +1135,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1245,7 +1246,7 @@ msgstr "reti di fornitori" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1384,7 +1385,7 @@ msgstr "Completato" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Fallito" @@ -1531,8 +1532,8 @@ msgid "User name" msgstr "Nome utente" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1632,7 +1633,7 @@ msgid "Completed before" msgstr "Completato prima" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1693,9 +1694,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Elevazioni dei rack" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Energia" @@ -2233,11 +2234,11 @@ msgstr "Lavoro {id} è stato fermato." msgid "Failed to stop job {id}" msgstr "Interruzione del lavoro non riuscita {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Impossibile caricare il catalogo dei plugin" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} non trovato" @@ -2255,7 +2256,7 @@ msgid "Staging" msgstr "Messa in scena" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Smantellamento" @@ -2315,7 +2316,7 @@ msgstr "Obsoleto" msgid "Millimeters" msgstr "Millimetri" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Pollici" @@ -2327,8 +2328,8 @@ msgstr "Da anteriore a posteriore" msgid "Rear to front" msgstr "Posteriore/anteriore" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2402,7 +2403,7 @@ msgstr "Dal basso verso l'alto" msgid "Top to bottom" msgstr "Dall'alto verso il basso" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passivo" @@ -2430,8 +2431,8 @@ msgstr "Internazionale/ITA" msgid "Proprietary" msgstr "Proprietario" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Altro" @@ -2444,22 +2445,22 @@ msgstr "ITA/Internazionale" msgid "Physical" msgstr "Fisico" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtuale" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Wireless" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Interfacce virtuali" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2469,155 +2470,155 @@ msgstr "Interfacce virtuali" msgid "Bridge" msgstr "ponte" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Link Aggregation Group (GAL)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fisso)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modulare)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (backplane)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Cellulare" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Seriale" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Coassiale" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "impilamento" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Metà" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Completo" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Auto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Accesso" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Taggato" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Contrassegnati (tutti)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Norma IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "24V passivo (2 coppie)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "24V passivo (4 coppie)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "48V passivo (2 coppie)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "48V passivo (4 coppie)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Rame" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Fibra ottica" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fibra" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Connesso" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Chilometri" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Metri" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centimetri" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Miglia" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Piedi" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Chilogrammi" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Grammi" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Sterline" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Once" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Ridondante" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Monofase" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Trifase" @@ -2850,7 +2851,7 @@ msgstr "Gruppo cluster (ID)" msgid "Device model (slug)" msgstr "Modello del dispositivo (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "È a piena profondità" @@ -2966,7 +2967,7 @@ msgstr "VLAN assegnata" msgid "Assigned VID" msgstr "VID assegnato" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3127,27 +3128,27 @@ msgstr "" "Sono supportati gli intervalli alfanumerici. (Deve corrispondere al numero " "di nomi da creare.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Nome del contatto" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Telefono di contatto" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "E-mail di contatto" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Fuso orario" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3170,51 +3171,51 @@ msgstr "Fuso orario" msgid "Manufacturer" msgstr "Produttore" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Fattore di forma" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Larghezza" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Altezza (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Unità discendenti" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Larghezza esterna" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Profondità esterna" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Unità esterna" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Profondità di montaggio" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3235,13 +3236,13 @@ msgstr "Profondità di montaggio" msgid "Weight" msgstr "Peso" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Peso massimo" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3249,31 +3250,31 @@ msgstr "Peso massimo" msgid "Weight unit" msgstr "Unità di peso" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Tipo di rack" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Dimensioni esterne" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensioni" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numerazione" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3313,21 +3314,21 @@ msgstr "Numerazione" msgid "Role" msgstr "Ruolo" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Numero di serie" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Etichetta dell'asset" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3337,7 +3338,7 @@ msgstr "Etichetta dell'asset" msgid "Airflow" msgstr "Flusso d'aria" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3357,7 +3358,7 @@ msgstr "Flusso d'aria" msgid "Rack" msgstr "cremagliera" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3366,49 +3367,49 @@ msgstr "cremagliera" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Piattaforma predefinita" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Numero del pezzo" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Altezza U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Escludi dall'utilizzo" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Tipo di dispositivo" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Tipo di modulo" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Telaio" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Ruolo VM" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3421,19 +3422,19 @@ msgstr "Ruolo VM" msgid "Config template" msgstr "Modello di configurazione" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Tipo di dispositivo" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Ruolo del dispositivo" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3447,8 +3448,28 @@ msgstr "Ruolo del dispositivo" msgid "Platform" msgstr "piattaforma" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Grappolo" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3505,22 +3526,27 @@ msgstr "piattaforma" msgid "Device" msgstr "Dispositivo" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Configurazione" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualizzazione" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Tipo di modulo" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3532,82 +3558,82 @@ msgstr "Tipo di modulo" msgid "Label" msgstr "Etichetta" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Lunghezza" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Unità di lunghezza" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Dominio" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Pannello di alimentazione" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Fornitura" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Voltaggio" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Amperaggio" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Utilizzo massimo" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Pareggio massimo" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Potenza massima assorbita (watt)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Pareggio assegnato" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Potenza assorbita allocata (watt)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Porta di alimentazione" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Gamba di alimentazione" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Solo gestione" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3615,7 +3641,7 @@ msgstr "Solo gestione" msgid "PoE mode" msgstr "modalità PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3623,12 +3649,12 @@ msgstr "modalità PoE" msgid "PoE type" msgstr "Tipo PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Ruolo wireless" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3638,16 +3664,16 @@ msgstr "Ruolo wireless" msgid "Module" msgstr "Modulo" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "RITARDO" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Contesti dei dispositivi virtuali" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3656,7 +3682,7 @@ msgstr "Contesti dei dispositivi virtuali" msgid "Speed" msgstr "Velocità" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3667,36 +3693,44 @@ msgstr "Velocità" msgid "Mode" msgstr "modalità" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Gruppo VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN senza tag" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Taggato VLAN" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Gruppo LAN wireless" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "LAN wireless" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3704,34 +3738,38 @@ msgstr "LAN wireless" msgid "Addressing" msgstr "Indirizzamento" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operazione" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Interfacce correlate" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Commutazione 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "" "La modalità di interfaccia deve essere specificata per assegnare le VLAN" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "" "A un'interfaccia di accesso non possono essere assegnate VLAN con tag." @@ -3873,26 +3911,6 @@ msgstr "Piattaforma assegnata" msgid "Virtual chassis" msgstr "Chassis virtuale" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Grappolo" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Cluster di virtualizzazione" @@ -6657,32 +6675,32 @@ msgstr "Si è verificato un errore durante il rendering del modello: {error}" msgid "Virtual Machines" msgstr "Macchine virtuali" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Dispositivo installato {device} nella baia {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Dispositivo rimosso {device} dalla baia {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Bambini" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Membro aggiunto {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "Impossibile rimuovere il dispositivo master {device} dallo chassis virtuale." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Rimosso {device} da chassis virtuale {chassis}" @@ -7634,19 +7652,19 @@ msgstr "Pianifica l'esecuzione dello script a un orario prestabilito" msgid "Interval at which this script is re-run (in minutes)" msgstr "Intervallo di riesecuzione dello script (in minuti)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Le modifiche al database sono state annullate automaticamente." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Script interrotto con errore: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Si è verificata un'eccezione: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Le modifiche al database sono state annullate a causa di un errore." @@ -8979,7 +8997,7 @@ msgstr "Gruppo VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9236,7 +9254,7 @@ msgstr "Assegnata a un'interfaccia" msgid "DNS Name" msgstr "Nome DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9246,7 +9264,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "Contiene l'ID VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "ID VLAN" @@ -9712,40 +9730,48 @@ msgstr "Impossibile impostare scope_type senza scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Impossibile impostare scope_id senza scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Gli intervalli non possono sovrapporsi." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Il VID massimo per bambini deve essere maggiore o uguale al VID minimo per " -"bambini ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Il sito specifico a cui è assegnata questa VLAN (se presente)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Gruppo VLAN (opzionale)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "ID VLAN numerico (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Stato operativo di questa VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "La funzione principale di questa VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9754,7 +9780,7 @@ msgstr "" "La VLAN è assegnata al gruppo {group} (scopo: {scope}); non può essere " "assegnato anche al sito {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10510,10 +10536,6 @@ msgstr "Criteri IPSec" msgid "IPSec Profiles" msgstr "Profili IPSec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualizzazione" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10922,19 +10944,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Fila {i}: Oggetto con ID {id} non esiste" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "No {object_type} sono stati selezionati." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Rinominato {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Eliminato {count} {object_type}" @@ -10966,7 +10988,7 @@ msgstr "Sincronizzato {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} deve implementare get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12828,7 +12850,7 @@ msgid "You do not have permission to run scripts" msgstr "Non si dispone dell'autorizzazione per eseguire gli script" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Esegui script" @@ -12840,27 +12862,32 @@ msgstr "Errore durante il caricamento dello script" msgid "Script no longer exists in the source file." msgstr "Lo script non esiste più nel file sorgente." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Ultima corsa" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Lo script non è più presente nel file sorgente" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Mai" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Corri ancora" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Nessuno script trovato" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14717,13 +14744,13 @@ msgid "Memory (MB)" msgstr "Memoria (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disco (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Dimensioni (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/ja/LC_MESSAGES/django.mo b/netbox/translations/ja/LC_MESSAGES/django.mo index db3175091..a3ce9ca9a 100644 Binary files a/netbox/translations/ja/LC_MESSAGES/django.mo and b/netbox/translations/ja/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/ja/LC_MESSAGES/django.po b/netbox/translations/ja/LC_MESSAGES/django.po index b86f59030..511e6a7ea 100644 --- a/netbox/translations/ja/LC_MESSAGES/django.po +++ b/netbox/translations/ja/LC_MESSAGES/django.po @@ -5,17 +5,17 @@ # # Translators: # Tatsuya Ueda , 2024 -# teapot, 2024 # Jeremy Stretch, 2024 +# teapot, 2024 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" -"Last-Translator: Jeremy Stretch, 2024\n" +"Last-Translator: teapot, 2024\n" "Language-Team: Japanese (https://app.transifex.com/netbox-community/teams/178115/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -84,8 +84,8 @@ msgid "Your password has been changed successfully." msgstr "パスワードは正常に変更されました。" #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "計画中" @@ -96,7 +96,7 @@ msgstr "プロビジョニング" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -106,7 +106,7 @@ msgid "Active" msgstr "アクティブ" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "オフライン" @@ -119,7 +119,7 @@ msgstr "デプロビジョニング" msgid "Decommissioned" msgstr "廃止" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "プライマリ" @@ -178,8 +178,8 @@ msgstr "サイトグループ (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -344,7 +344,7 @@ msgstr "回線グループ (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -356,21 +356,21 @@ msgstr "ASN" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -411,7 +411,7 @@ msgstr "ASN" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -478,9 +478,9 @@ msgid "Service ID" msgstr "サービス ID" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -497,11 +497,11 @@ msgstr "色" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -546,11 +546,11 @@ msgstr "プロバイダアカウント" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -577,7 +577,7 @@ msgstr "プロバイダアカウント" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -602,10 +602,10 @@ msgstr "ステータス" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -709,11 +709,11 @@ msgstr "ポートスピード (Kbps)" msgid "Upstream speed (Kbps)" msgstr "アップストリーム速度 (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "接続済みにする" @@ -791,9 +791,9 @@ msgid "Provider network" msgstr "プロバイダネットワーク" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -840,8 +840,8 @@ msgid "Contacts" msgstr "連絡先" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -864,7 +864,7 @@ msgid "Region" msgstr "リージョン" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -882,7 +882,7 @@ msgstr "サイトグループ" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -917,16 +917,17 @@ msgstr "アカウント" msgid "Term Side" msgstr "タームサイド" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "割当" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -992,7 +993,7 @@ msgstr "一意な回線 ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1127,7 +1128,7 @@ msgstr "回線終端をサイトとプロバイダーネットワークの両方 #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1238,7 +1239,7 @@ msgstr "プロバイダネットワーク" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1375,7 +1376,7 @@ msgstr "完了" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "失敗" @@ -1522,8 +1523,8 @@ msgid "User name" msgstr "ユーザ名" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1623,7 +1624,7 @@ msgid "Completed before" msgstr "以前に完了" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1683,9 +1684,9 @@ msgstr "同期するファイルをアップロードするか、データファ msgid "Rack Elevations" msgstr "ラック図" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "電源" @@ -2211,11 +2212,11 @@ msgstr "ジョブ {id} 停止されました。" msgid "Failed to stop job {id}" msgstr "ジョブを停止できませんでした {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "プラグインカタログを読み込めませんでした" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "プラグイン {name} が見つかりません" @@ -2233,7 +2234,7 @@ msgid "Staging" msgstr "ステージング" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "廃止" @@ -2293,7 +2294,7 @@ msgstr "廃止済" msgid "Millimeters" msgstr "ミリメートル" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "インチ" @@ -2305,8 +2306,8 @@ msgstr "前面から背面" msgid "Rear to front" msgstr "背面から前面" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2380,7 +2381,7 @@ msgstr "下から上へ" msgid "Top to bottom" msgstr "上から下へ" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "パッシブ" @@ -2408,8 +2409,8 @@ msgstr "International/ITA" msgid "Proprietary" msgstr "独自規格" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "その他" @@ -2422,22 +2423,22 @@ msgstr "ITA/International" msgid "Physical" msgstr "物理" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "仮想" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "無線" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "仮想インタフェース" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2447,155 +2448,155 @@ msgstr "仮想インタフェース" msgid "Bridge" msgstr "ブリッジ" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "リンクアグリゲーション (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "イーサネット (固定)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "イーサネット (モジュール)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "イーサネット (バックプレーン)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "セルラー" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "シリアル" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "同軸" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "スタック" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "半二重" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "全二重" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "自動" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "アクセス" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "タグ付き" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "タグ付き (全て)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE スタンダード" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "パッシブ 24V (2 ペア)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "パッシブ 24V (4ペア)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "パッシブ 48V (2 ペア)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "パッシブ 48V (4ペア)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "カッパー" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "光ファイバー" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "ファイバー" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "接続済" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "キロメートル" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "メートル" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "センチメートル" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "マイル" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "フィート" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "キログラム" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "グラム" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "ポンド" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "オンス" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "冗長" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "単相" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "三相" @@ -2828,7 +2829,7 @@ msgstr "クラスタグループ (ID)" msgid "Device model (slug)" msgstr "デバイスモデル (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "奥行きをすべて使うか" @@ -2944,7 +2945,7 @@ msgstr "割当 VLAN" msgid "Assigned VID" msgstr "割当 VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3103,27 +3104,27 @@ msgid "" "created.)" msgstr "英数字の範囲が使用できます。(作成する名前の数と一致する必要があります)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "連絡先名" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "連絡先電話番号" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "連絡先電子メール" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "タイムゾーン" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3146,51 +3147,51 @@ msgstr "タイムゾーン" msgid "Manufacturer" msgstr "メーカ" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "フォームファクタ" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "幅" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "高さ (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "降順" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "外形の幅" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "外形の奥行" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "外形の単位" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "取り付け奥行き" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3211,13 +3212,13 @@ msgstr "取り付け奥行き" msgid "Weight" msgstr "重量" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "最大重量" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3225,31 +3226,31 @@ msgstr "最大重量" msgid "Weight unit" msgstr "重量単位" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "ラックタイプ" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "外形寸法" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "寸法" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "ナンバリング" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3289,21 +3290,21 @@ msgstr "ナンバリング" msgid "Role" msgstr "ロール" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "シリアル番号" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "アセットタグ" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3313,7 +3314,7 @@ msgstr "アセットタグ" msgid "Airflow" msgstr "エアフロー" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3333,7 +3334,7 @@ msgstr "エアフロー" msgid "Rack" msgstr "ラック" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3342,49 +3343,49 @@ msgstr "ラック" msgid "Hardware" msgstr "ハードウェア" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "デフォルトプラットフォーム" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "パーツ番号" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "ユニット数" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "ラック利用率に含めない" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "デバイスタイプ" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "モジュールタイプ" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "シャーシ" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VMのロール" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3397,19 +3398,19 @@ msgstr "VMのロール" msgid "Config template" msgstr "設定テンプレート" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "デバイスタイプ" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "デバイスロール" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3423,8 +3424,28 @@ msgstr "デバイスロール" msgid "Platform" msgstr "プラットフォーム" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "クラスタ" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3481,22 +3502,27 @@ msgstr "プラットフォーム" msgid "Device" msgstr "デバイス" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "設定" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "仮想化" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "モジュールタイプ" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3508,82 +3534,82 @@ msgstr "モジュールタイプ" msgid "Label" msgstr "ラベル" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "長さ" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "長さの単位" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "ドメイン" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "電源盤" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "供給電源" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "電力相" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "電圧" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "アンペア数" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "最大使用率" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "最大消費電力" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "最大消費電力 (ワット)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "割当電力" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "割当消費電力 (ワット)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "電源ポート" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "供給端子" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "管理のみ" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3591,7 +3617,7 @@ msgstr "管理のみ" msgid "PoE mode" msgstr "PoE モード" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3599,12 +3625,12 @@ msgstr "PoE モード" msgid "PoE type" msgstr "PoE タイプ" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "無線ロール" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3614,16 +3640,16 @@ msgstr "無線ロール" msgid "Module" msgstr "モジュール" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "仮想デバイスコンテキスト" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3632,7 +3658,7 @@ msgstr "仮想デバイスコンテキスト" msgid "Speed" msgstr "速度" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3643,36 +3669,44 @@ msgstr "速度" msgid "Mode" msgstr "モード" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN グループ" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "タグなし VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "タグ付き VLAN" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "タグ付 VLAN の追加" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "タグ付 VLAN の削除" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "無線 LAN グループ" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "無線 LAN" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3680,33 +3714,37 @@ msgstr "無線 LAN" msgid "Addressing" msgstr "アドレス" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "オペレーション" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "関連インタフェース" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q スイッチング" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "追加/削除" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "VLAN を割り当てるには、インタフェースモードを指定する必要があります" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "アクセスインタフェースにはタグ付き VLAN を割り当てることはできません。" @@ -3847,26 +3885,6 @@ msgstr "割当プラットフォーム" msgid "Virtual chassis" msgstr "バーチャルシャーシ" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "クラスタ" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "仮想化クラスタ" @@ -6478,31 +6496,31 @@ msgstr "テンプレートをレンダリング中にエラーが発生しまし msgid "Virtual Machines" msgstr "仮想マシン" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "インストール済みデバイス {device} イン・ベイ {device_bay}。" -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "削除されたデバイス {device} ベイから {device_bay}。" -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "子ども" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "メンバー追加 {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "マスターデバイスを削除できません {device} バーチャルシャーシから。" -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "削除済み {device} バーチャルシャーシから {chassis}" @@ -7424,19 +7442,19 @@ msgstr "スクリプトの実行をスケジュールする" msgid "Interval at which this script is re-run (in minutes)" msgstr "実行される間隔 (分単位)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "データベースの変更は自動的に元に戻されました。" -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "スクリプトがエラーで中止されました: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "例外が発生しました: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "エラーにより、データベースの変更が元に戻されました。" @@ -8714,7 +8732,7 @@ msgstr "VLAN グループ" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -8968,7 +8986,7 @@ msgstr "インタフェースに割当済" msgid "DNS Name" msgstr "DNS名" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -8978,7 +8996,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "VLAN ID が含まれています" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN ID" @@ -9416,45 +9434,55 @@ msgstr "scope_id なしでscope_typeを設定することはできません。" msgid "Cannot set scope_id without scope_type." msgstr "scope_typeなしでscope_idを設定することはできません。" -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "範囲は重複できません。" -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "子供 VID の最大数は、子供 VID の最小値以上でなければなりません ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "この VLAN が割り当てられているサイト (存在する場合)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN グループ (オプション)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "数値によるVLAN ID (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "この VLAN の動作ステータス" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "この VLAN の主な機能" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " "site {site}." msgstr "VLANはグループ{group}に割り当てられています (スコープ: {scope}) サイト{site}への割り当てはできません 。" -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID は範囲内にある必要があります {ranges} グループ内の VLAN 用 {group}" @@ -10187,10 +10215,6 @@ msgstr "IPsec ポリシ" msgid "IPSec Profiles" msgstr "IPsec プロファイル" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "仮想化" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10589,19 +10613,19 @@ msgstr "選択したエクスポートテンプレートをレンダリング中 msgid "Row {i}: Object with ID {id} does not exist" msgstr "行 {i}: ID {id}のオブジェクトは存在しません" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "いいえ {object_type} が選ばれました。" -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "名前が変更されました {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "削除済み {count} {object_type}" @@ -10633,7 +10657,7 @@ msgstr "同期済み {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} はget_children () を実装する必要があります" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12466,7 +12490,7 @@ msgid "You do not have permission to run scripts" msgstr "スクリプトを実行する権限がありません" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "スクリプトを実行" @@ -12478,27 +12502,32 @@ msgstr "スクリプトのロード中にエラーが発生しました" msgid "Script no longer exists in the source file." msgstr "スクリプトはソースファイルに存在しなくなりました。" -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "ラストラン" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "スクリプトはソースファイルに存在しなくなりました" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "決して" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "もう一度実行" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "モジュール%(module)sからスクリプトを読み込めませんでした " + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "スクリプトが見つかりません" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14292,13 +14321,13 @@ msgid "Memory (MB)" msgstr "メモリ (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "ディスク (GB)" +msgid "Disk (MB)" +msgstr "ディスク (MB)" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "サイズ (GB)" +msgid "Size (MB)" +msgstr "サイズ (MB)" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" @@ -14362,7 +14391,7 @@ msgstr "クラスタグループ" #: virtualization/models/clusters.py:121 msgid "cluster" -msgstr "集まる" +msgstr "クラスタ" #: virtualization/models/clusters.py:122 msgid "clusters" diff --git a/netbox/translations/nl/LC_MESSAGES/django.mo b/netbox/translations/nl/LC_MESSAGES/django.mo index ca93c83dc..46dadac28 100644 Binary files a/netbox/translations/nl/LC_MESSAGES/django.mo and b/netbox/translations/nl/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/nl/LC_MESSAGES/django.po b/netbox/translations/nl/LC_MESSAGES/django.po index 175331f93..0182ae0d8 100644 --- a/netbox/translations/nl/LC_MESSAGES/django.po +++ b/netbox/translations/nl/LC_MESSAGES/django.po @@ -8,6 +8,7 @@ # deku_m, 2024 # Peter Mulder , 2024 # Jeremy Stretch, 2024 +# Jorg de Jong, 2024 # Sebastian Berm, 2024 # #, fuzzy @@ -15,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Sebastian Berm, 2024\n" "Language-Team: Dutch (https://app.transifex.com/netbox-community/teams/178115/nl/)\n" @@ -88,8 +89,8 @@ msgid "Your password has been changed successfully." msgstr "Je wachtwoord is succesvol gewijzigd." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Gepland" @@ -100,7 +101,7 @@ msgstr "Provisioning" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -110,7 +111,7 @@ msgid "Active" msgstr "Actief" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Offline" @@ -123,7 +124,7 @@ msgstr "Deprovisioning" msgid "Decommissioned" msgstr "Buiten gebruik" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primair" @@ -182,8 +183,8 @@ msgstr "Sitegroep (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -348,7 +349,7 @@ msgstr "Circuitgroep (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -360,21 +361,21 @@ msgstr "ASN's" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -415,7 +416,7 @@ msgstr "ASN's" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -482,9 +483,9 @@ msgid "Service ID" msgstr "Service-ID" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -501,11 +502,11 @@ msgstr "Kleur" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -550,11 +551,11 @@ msgstr "Provideraccount" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -581,7 +582,7 @@ msgstr "Provideraccount" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -606,10 +607,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -713,11 +714,11 @@ msgstr "Poortsnelheid (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Upstreamsnelheid (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Markeren als verbonden" @@ -795,9 +796,9 @@ msgid "Provider network" msgstr "Netwerkprovider" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -844,8 +845,8 @@ msgid "Contacts" msgstr "Contacten" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -868,7 +869,7 @@ msgid "Region" msgstr "Regio" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -886,7 +887,7 @@ msgstr "Sitegroep" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -921,16 +922,17 @@ msgstr "Account" msgid "Term Side" msgstr "Termzijde" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Opdracht" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -996,7 +998,7 @@ msgstr "Uniek circuit-ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1135,7 +1137,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1246,7 +1248,7 @@ msgstr "providernetwerken" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1385,7 +1387,7 @@ msgstr "Voltooid" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Mislukt" @@ -1532,8 +1534,8 @@ msgid "User name" msgstr "Gebruikersnaam" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1633,7 +1635,7 @@ msgid "Completed before" msgstr "Eerder voltooid" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1696,9 +1698,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Rackverhogingen" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Stroom" @@ -2234,11 +2236,11 @@ msgstr "Baan {id} is gestopt." msgid "Failed to stop job {id}" msgstr "Kon de taak niet stoppen {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "De catalogus met plug-ins kon niet worden geladen" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plug-in {name} niet gevonden" @@ -2256,7 +2258,7 @@ msgid "Staging" msgstr "Klaarzetten" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Ontmanteling" @@ -2316,7 +2318,7 @@ msgstr "Verouderd" msgid "Millimeters" msgstr "Millimeters" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Inches" @@ -2328,8 +2330,8 @@ msgstr "Van voor naar achter" msgid "Rear to front" msgstr "Van achter naar voren" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2403,7 +2405,7 @@ msgstr "Van onder naar boven" msgid "Top to bottom" msgstr "Van boven naar beneden" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passief" @@ -2431,8 +2433,8 @@ msgstr "Internationaal/ITA" msgid "Proprietary" msgstr "Gepatenteerd" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Andere" @@ -2445,22 +2447,22 @@ msgstr "ITA/internationaal" msgid "Physical" msgstr "Fysiek" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtueel" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Draadloos" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Virtuele interfaces" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2470,155 +2472,155 @@ msgstr "Virtuele interfaces" msgid "Bridge" msgstr "Bridge" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Linkaggregatiegroep (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (vast)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modulair)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (backplane)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Mobiel" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Serienummer" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Coaxiaal" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Stapelen" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Half" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Volledig" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Auto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Toegang" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Getagd" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Getagd (Alles)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE-standaard" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Passief 24V (2 paren)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Passief 24V (4 paren)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Passief 48V (2 paren)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Passief 48V (4 paren)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Koper" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Glasvezel" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Vezel" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Verbonden" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometers" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Meters" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centimeters" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Mijlen" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Feet" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogrammen" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gram" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Ponden" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Ons" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundant" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Een fase" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Drie fase" @@ -2851,7 +2853,7 @@ msgstr "Clustergroep (ID)" msgid "Device model (slug)" msgstr "Apparaatmodel (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Is volledige diepte" @@ -2967,7 +2969,7 @@ msgstr "Toegewezen VLAN" msgid "Assigned VID" msgstr "Toegewezen VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3128,27 +3130,27 @@ msgstr "" "Alfanumerieke reeksen worden ondersteund. (Moet overeenkomen met het aantal " "namen dat wordt aangemaakt.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Naam van de contactpersoon" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Telefoonnummer contacteren" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "E-mailadres voor contact" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Tijdzone" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3171,51 +3173,51 @@ msgstr "Tijdzone" msgid "Manufacturer" msgstr "Fabrikant" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Vormfactor" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Breedte" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Hoogte (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Aflopende eenheden" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Buitenbreedte" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Buitendiepte" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Buitenste eenheid" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Inbouwdiepte" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3236,13 +3238,13 @@ msgstr "Inbouwdiepte" msgid "Weight" msgstr "Gewicht" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Maximaal gewicht" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3250,31 +3252,31 @@ msgstr "Maximaal gewicht" msgid "Weight unit" msgstr "Gewichtseenheid" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Racktype" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Buitenafmetingen" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensies" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Nummering" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3314,21 +3316,21 @@ msgstr "Nummering" msgid "Role" msgstr "Rol" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Serienummer" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Tag voor bedrijfsmiddelen" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3338,7 +3340,7 @@ msgstr "Tag voor bedrijfsmiddelen" msgid "Airflow" msgstr "Luchtstroom" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3358,7 +3360,7 @@ msgstr "Luchtstroom" msgid "Rack" msgstr "Rek" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3367,49 +3369,49 @@ msgstr "Rek" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Standaardplatform" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Onderdeelnummer" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "U-hoogte" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Uitsluiten van gebruik" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Soort apparaat" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Moduletype" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Chassis" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VM-rol" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3422,19 +3424,19 @@ msgstr "VM-rol" msgid "Config template" msgstr "Configuratiesjabloon" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Soort apparaat" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Rol van het apparaat" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3448,8 +3450,28 @@ msgstr "Rol van het apparaat" msgid "Platform" msgstr "Platform" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Cluster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3506,22 +3528,27 @@ msgstr "Platform" msgid "Device" msgstr "Apparaat" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Configuratie" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualisatie" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Moduletype" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3533,82 +3560,82 @@ msgstr "Moduletype" msgid "Label" msgstr "Label" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Lengte" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Lengte-eenheid" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Domein" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Voedingspaneel" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Levering" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Spanning" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Stroomsterkte" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Maximaal gebruik" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maximale trekking" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maximaal stroomverbruik (watt)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Toegewezen loting" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Toegewezen stroomverbruik (watt)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Voedingspoort" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Voer de poot in" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Alleen voor beheer" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3616,7 +3643,7 @@ msgstr "Alleen voor beheer" msgid "PoE mode" msgstr "PoE-modus" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3624,12 +3651,12 @@ msgstr "PoE-modus" msgid "PoE type" msgstr "PoE-type" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Draadloze rol" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3639,16 +3666,16 @@ msgstr "Draadloze rol" msgid "Module" msgstr "Module" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Contexten van virtuele apparaten" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3657,7 +3684,7 @@ msgstr "Contexten van virtuele apparaten" msgid "Speed" msgstr "Snelheid" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3668,36 +3695,44 @@ msgstr "Snelheid" msgid "Mode" msgstr "Modus" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN-groep" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN zonder label" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Getagde VLAN's" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Draadloze LAN-groep" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Draadloze LAN's" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3705,33 +3740,37 @@ msgstr "Draadloze LAN's" msgid "Addressing" msgstr "Addressing" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operatie" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Gerelateerde interfaces" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q-omschakeling" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "De interfacemodus moet worden gespecificeerd om VLAN's toe te wijzen" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "" "Aan een toegangsinterface kunnen geen gelabelde VLAN's worden toegewezen." @@ -3873,26 +3912,6 @@ msgstr "Toegewezen platform" msgid "Virtual chassis" msgstr "Virtueel chassis" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Cluster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Virtualisatiecluster" @@ -6636,32 +6655,32 @@ msgstr "" msgid "Virtual Machines" msgstr "Virtuele machines" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Geïnstalleerd apparaat {device} in de baai {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Apparaat verwijderd {device} van bay {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Kinderen" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Lid toegevoegd {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "Kan het masterapparaat niet verwijderen {device} vanaf het virtuele chassis." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Verwijderd {device} vanaf een virtueel chassis {chassis}" @@ -7615,19 +7634,19 @@ msgstr "Plan de uitvoering van het script op een bepaald tijdstip" msgid "Interval at which this script is re-run (in minutes)" msgstr "Interval waarmee dit script opnieuw wordt uitgevoerd (in minuten)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Wijzigingen in de database zijn automatisch teruggedraaid." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Script is met een fout afgebroken: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Er deed zich een uitzondering voor: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Wijzigingen in de database zijn teruggedraaid vanwege een fout." @@ -8959,7 +8978,7 @@ msgstr "VLAN-groep" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -8977,7 +8996,7 @@ msgstr "Lengte van het voorvoegsel" #: ipam/forms/bulk_edit.py:268 ipam/forms/filtersets.py:241 #: templates/ipam/prefix.html:85 msgid "Is a pool" -msgstr "Is een zwembad" +msgstr "Is een pool" #: ipam/forms/bulk_edit.py:273 ipam/forms/bulk_edit.py:318 #: ipam/forms/filtersets.py:248 ipam/forms/filtersets.py:293 @@ -9217,7 +9236,7 @@ msgstr "Toegewezen aan een interface" msgid "DNS Name" msgstr "DNS-naam" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9227,7 +9246,7 @@ msgstr "VLAN's" msgid "Contains VLAN ID" msgstr "Bevat VLAN-ID" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN-ID" @@ -9692,40 +9711,48 @@ msgstr "Kan scope_type niet instellen zonder scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Kan scope_id niet instellen zonder scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Bereiken kunnen elkaar niet overlappen." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"De maximale VID voor kinderen moet groter zijn dan of gelijk zijn aan de " -"minimale VID voor kinderen ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "De specifieke site waaraan dit VLAN is toegewezen (indien aanwezig)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN-groep (optioneel)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Numerieke VLAN-id (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Operationele status van dit VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "De primaire functie van dit VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9734,7 +9761,7 @@ msgstr "" "VLAN is toegewezen aan de groep {group} (toepassingsgebied: {scope}); kan " "niet ook aan de site worden toegewezen {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID moet binnen bereik zijn {ranges} voor VLAN's in groep {group}" @@ -10488,10 +10515,6 @@ msgstr "IPsec-beleid" msgid "IPSec Profiles" msgstr "IPsec-profielen" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualisatie" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10898,19 +10921,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Rij {i}: Object met ID {id} bestaat niet" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Nee {object_type} zijn geselecteerd." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Hernoemd {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Verwijderd {count} {object_type}" @@ -10943,7 +10966,7 @@ msgstr "Gesynchroniseerd {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} moet get_children () implementeren" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12806,7 +12829,7 @@ msgid "You do not have permission to run scripts" msgstr "Je hebt geen toestemming om scripts uit te voeren" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Script uitvoeren" @@ -12818,27 +12841,32 @@ msgstr "Fout bij laden van script" msgid "Script no longer exists in the source file." msgstr "Het script bestaat niet meer in het bronbestand." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Laatste run" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Het script is niet langer aanwezig in het bronbestand" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Nooit" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Draai opnieuw" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "Kon de scripts van niet laden van module %(module)s" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Geen scripts gevonden" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14697,13 +14725,13 @@ msgid "Memory (MB)" msgstr "Geheugen (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Schijf (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Grootte (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/pl/LC_MESSAGES/django.mo b/netbox/translations/pl/LC_MESSAGES/django.mo index 64ee5ba08..a9c8d9fe7 100644 Binary files a/netbox/translations/pl/LC_MESSAGES/django.mo and b/netbox/translations/pl/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/pl/LC_MESSAGES/django.po b/netbox/translations/pl/LC_MESSAGES/django.po index 50a8f6f40..07567c147 100644 --- a/netbox/translations/pl/LC_MESSAGES/django.po +++ b/netbox/translations/pl/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Grzegorz Szymaszek, 2024\n" "Language-Team: Polish (https://app.transifex.com/netbox-community/teams/178115/pl/)\n" @@ -87,8 +87,8 @@ msgid "Your password has been changed successfully." msgstr "Twoje hasło zostało pomyślnie zmienione." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planowane" @@ -99,7 +99,7 @@ msgstr "Zaopatrzenie" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -109,7 +109,7 @@ msgid "Active" msgstr "Aktywny" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Nieaktywne" @@ -122,7 +122,7 @@ msgstr "Odstąpienie od zaopatrzenia" msgid "Decommissioned" msgstr "Wycofane ze służby" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Pierwszorzędny" @@ -181,8 +181,8 @@ msgstr "Grupa terenów (identyfikator)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -347,7 +347,7 @@ msgstr "Grupa obwodów (identyfikator)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -359,21 +359,21 @@ msgstr "ASN" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -414,7 +414,7 @@ msgstr "ASN" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -481,9 +481,9 @@ msgid "Service ID" msgstr "Identyfikator usługi" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -500,11 +500,11 @@ msgstr "Kolor" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -549,11 +549,11 @@ msgstr "Konto dostawcy" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -580,7 +580,7 @@ msgstr "Konto dostawcy" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -605,10 +605,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -712,11 +712,11 @@ msgstr "Prędkość portu (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Prędkość od klienta do serwera (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Oznacz podłączony" @@ -794,9 +794,9 @@ msgid "Provider network" msgstr "Sieć dostawców" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -843,8 +843,8 @@ msgid "Contacts" msgstr "Łączność" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -867,7 +867,7 @@ msgid "Region" msgstr "Region" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -885,7 +885,7 @@ msgstr "Grupa terenów" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -920,16 +920,17 @@ msgstr "Konto" msgid "Term Side" msgstr "Strona terminowa" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Zlecenie" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -995,7 +996,7 @@ msgstr "Unikalny identyfikator obwodu" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1132,7 +1133,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1243,7 +1244,7 @@ msgstr "sieci dostawców" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1380,7 +1381,7 @@ msgstr "Zakończone" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Nie powiodło się" @@ -1527,8 +1528,8 @@ msgid "User name" msgstr "Nazwa użytkownika" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1628,7 +1629,7 @@ msgid "Completed before" msgstr "Zakończone przed" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1688,9 +1689,9 @@ msgstr "Musisz przesłać plik lub wybrać plik danych do synchronizacji" msgid "Rack Elevations" msgstr "Elewacje szaf" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Moc" @@ -2223,11 +2224,11 @@ msgstr "Praca {id} został zatrzymany." msgid "Failed to stop job {id}" msgstr "Nie udało się zatrzymać zadania {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Nie można załadować katalogu wtyczek" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Wtyczka {name} nie znaleziono" @@ -2245,7 +2246,7 @@ msgid "Staging" msgstr "Inscenizacja" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Wycofanie z eksploatacji" @@ -2305,7 +2306,7 @@ msgstr "Przestarzałe" msgid "Millimeters" msgstr "Milimetrów" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Cale" @@ -2317,8 +2318,8 @@ msgstr "Przód do tyłu" msgid "Rear to front" msgstr "Tył do przodu" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2392,7 +2393,7 @@ msgstr "Od dołu do góry" msgid "Top to bottom" msgstr "Od góry do dołu" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Pasywny" @@ -2420,8 +2421,8 @@ msgstr "Międzynarodowy/ITA" msgid "Proprietary" msgstr "Własnościowy" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Pozostałe" @@ -2434,22 +2435,22 @@ msgstr "ITA/Międzynarodowy" msgid "Physical" msgstr "Fizyczne" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Wirtualny" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Bezprzewodowy" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Interfejsy wirtualne" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2459,155 +2460,155 @@ msgstr "Interfejsy wirtualne" msgid "Bridge" msgstr "Most" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Grupa agregacji linków (LGD)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (stały)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modułowy)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (płaszczyzna tylna)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Komórkowy" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Seryjny" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "koncentryczny" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Układanie" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Połowa" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Pełny" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Automatyczny" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Dostęp" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Oznaczone" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Oznaczone (Wszystkie)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Standard IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Pasywny 24V (2 pary)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Pasywny 24V (4-parowy)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Pasywny 48V (2 pary)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Pasywny 48V (4 pary)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Miedź" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Światłowód" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Włókno" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Połączony" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometry" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Mierniki" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centymetry" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Mile" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Stopy" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogramy" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramy" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "funty" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Uncja" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Nadmiarowy" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Jednofazowy" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Trójfazowy" @@ -2840,7 +2841,7 @@ msgstr "Grupa klastra (ID)" msgid "Device model (slug)" msgstr "Model urządzenia (identyfikator)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Jest pełna głębokość" @@ -2956,7 +2957,7 @@ msgstr "Przypisana sieć VLAN" msgid "Assigned VID" msgstr "Przypisany VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3117,27 +3118,27 @@ msgstr "" "Obsługiwane są zakresy alfanumeryczne. (Musi odpowiadać liczbie tworzonych " "nazw.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Nazwa kontaktu" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Telefon kontaktowy" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Kontakt E-mail" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Strefa czasowa" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3160,51 +3161,51 @@ msgstr "Strefa czasowa" msgid "Manufacturer" msgstr "Producent" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Współczynnik kształtu" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Szerokość" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Wysokość (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Jednostki malejące" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Szerokość zewnętrzna" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Głębokość zewnętrzna" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Jednostka zewnętrzna" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Głębokość montażu" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3225,13 +3226,13 @@ msgstr "Głębokość montażu" msgid "Weight" msgstr "Waga" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Maksymalna waga" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3239,31 +3240,31 @@ msgstr "Maksymalna waga" msgid "Weight unit" msgstr "Jednostka wagowa" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Typ szafy" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Wymiary zewnętrzne" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Wymiary" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numeracja" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3303,21 +3304,21 @@ msgstr "Numeracja" msgid "Role" msgstr "Rola" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Numer seryjny" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Etykieta zasobu" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3327,7 +3328,7 @@ msgstr "Etykieta zasobu" msgid "Airflow" msgstr "Przepływ powietrza" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3347,7 +3348,7 @@ msgstr "Przepływ powietrza" msgid "Rack" msgstr "Szafa" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3356,49 +3357,49 @@ msgstr "Szafa" msgid "Hardware" msgstr "Sprzęt" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Domyślna platforma" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Numer części" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Wysokość U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Wyklucz z wykorzystania" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Typ urządzenia" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Typ modułu" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Podwozie" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Rola maszyny wirtualnej" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3411,19 +3412,19 @@ msgstr "Rola maszyny wirtualnej" msgid "Config template" msgstr "Szablon konfiguracji" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Typ urządzenia" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Rola urządzenia" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3437,8 +3438,28 @@ msgstr "Rola urządzenia" msgid "Platform" msgstr "Platforma" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Klaster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3495,22 +3516,27 @@ msgstr "Platforma" msgid "Device" msgstr "Urządzenie" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Konfiguracja" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Wirtualizacja" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Rodzaj modułu" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3522,82 +3548,82 @@ msgstr "Rodzaj modułu" msgid "Label" msgstr "Etykieta" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Długość" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Jednostka długości" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Domena" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Panel zasilania" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Dostawa" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Faza" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Napięcie" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Natężenie prądu" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Maksymalne wykorzystanie" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maksymalne losowanie" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maksymalny pobór mocy (waty)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Przydzielone losowanie" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Przydzielony pobór mocy (waty)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Port zasilania" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Noga do karmienia" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Tylko zarządzanie" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3605,7 +3631,7 @@ msgstr "Tylko zarządzanie" msgid "PoE mode" msgstr "Tryb PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3613,12 +3639,12 @@ msgstr "Tryb PoE" msgid "PoE type" msgstr "Typ PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Rola sieci bezprzewodowej" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3628,16 +3654,16 @@ msgstr "Rola sieci bezprzewodowej" msgid "Module" msgstr "Moduł" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "OPÓŹNIENIE" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Konteksty urządzeń wirtualnych" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3646,7 +3672,7 @@ msgstr "Konteksty urządzeń wirtualnych" msgid "Speed" msgstr "Prędkość" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3657,36 +3683,44 @@ msgstr "Prędkość" msgid "Mode" msgstr "Tryb" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Grupa VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "Nieoznaczone sieci VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Oznaczone sieci VLAN" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Grupa sieci bezprzewodowej sieci LAN" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Bezprzewodowe sieci LAN" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3694,33 +3728,37 @@ msgstr "Bezprzewodowe sieci LAN" msgid "Addressing" msgstr "Adresowanie" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operacja" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Powiązane interfejsy" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Przełączanie 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Tryb interfejsu musi być określony, aby przypisać sieci VLAN" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Interfejs dostępu nie może mieć przypisanych oznakowanych sieci VLAN." @@ -3861,26 +3899,6 @@ msgstr "Przydzielona platforma" msgid "Virtual chassis" msgstr "Wirtualne podwozie" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Klaster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Klaster wirtualizacji" @@ -6598,31 +6616,31 @@ msgstr "Wystąpił błąd podczas renderowania szablonu: {error}" msgid "Virtual Machines" msgstr "Maszyny wirtualne" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Zainstalowane urządzenie {device} w zatoce {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Usunięte urządzenie {device} z zatoki {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Dzieci" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Dodano członka {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Nie można usunąć urządzenia głównego {device} z wirtualnego podwozia." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Usunięto {device} z wirtualnego podwozia {chassis}" @@ -7564,19 +7582,19 @@ msgstr "Zaplanuj wykonanie skryptu na określony czas" msgid "Interval at which this script is re-run (in minutes)" msgstr "Interwał, w którym ten skrypt jest ponownie uruchamiany (w minutach)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Zmiany w bazie danych zostały wycofane automatycznie." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Skrypt przerwany z błędem: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Wystąpił wyjątek: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Zmiany bazy danych zostały cofnięte z powodu błędu." @@ -8894,7 +8912,7 @@ msgstr "Grupa VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9151,7 +9169,7 @@ msgstr "Przypisany do interfejsu" msgid "DNS Name" msgstr "Nazwa DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9161,7 +9179,7 @@ msgstr "sieci VLAN" msgid "Contains VLAN ID" msgstr "Zawiera identyfikator VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "IDENTYFIKATOR VLAN" @@ -9620,41 +9638,49 @@ msgstr "Nie można ustawić typu skope_bez identyfikatora scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Nie można ustawić scope_id bez scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Zakresy nie mogą się nakładać." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Maksymalny VID dziecka musi być większy lub równy minimalnej wartości VID " -"dziecka ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "" "Określona strona, do której przypisana jest ta sieć VLAN (jeśli istnieje)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Grupa VLAN (opcjonalnie)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Numeryczny identyfikator sieci VLAN (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Stan operacyjny tej sieci VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Podstawowa funkcja tej VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9663,7 +9689,7 @@ msgstr "" "VLAN jest przypisana do grupy {group} (zakres: {scope}); nie można również " "przypisać do witryny {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID musi być w zakresach {ranges} dla sieci VLAN w grupie {group}" @@ -10410,10 +10436,6 @@ msgstr "Zasady IPsec" msgid "IPSec Profiles" msgstr "Profile IPsec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Wirtualizacja" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10819,19 +10841,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Wiersz {i}: Obiekt z identyfikatorem {id} nie istnieje" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Nie {object_type} zostały wybrane." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Zmiana nazwy {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Usunięte {count} {object_type}" @@ -10863,7 +10885,7 @@ msgstr "Zsynchronizowane {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} musi zaimplementować get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12719,7 +12741,7 @@ msgid "You do not have permission to run scripts" msgstr "Nie masz uprawnień do uruchamiania skryptów" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Uruchom skrypt" @@ -12731,27 +12753,32 @@ msgstr "Błąd ładowania skryptu" msgid "Script no longer exists in the source file." msgstr "Skrypt nie istnieje już w pliku źródłowym." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Ostatni bieg" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Skrypt nie jest już obecny w pliku źródłowym" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Nigdy" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Uruchom ponownie" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Nie znaleziono skryptów" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14605,13 +14632,13 @@ msgid "Memory (MB)" msgstr "Pamięć (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Dysk (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Rozmiar (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/pt/LC_MESSAGES/django.mo b/netbox/translations/pt/LC_MESSAGES/django.mo index 9a287344c..96c602259 100644 Binary files a/netbox/translations/pt/LC_MESSAGES/django.mo and b/netbox/translations/pt/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/pt/LC_MESSAGES/django.po b/netbox/translations/pt/LC_MESSAGES/django.po index 72135959b..d3ea03c89 100644 --- a/netbox/translations/pt/LC_MESSAGES/django.po +++ b/netbox/translations/pt/LC_MESSAGES/django.po @@ -6,17 +6,17 @@ # Translators: # Renato Almeida de Oliveira, 2023 # Fer22f , 2024 -# Fabricio Maciel, 2024 # Jeremy Stretch, 2024 +# Fabricio Maciel, 2024 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" -"Last-Translator: Jeremy Stretch, 2024\n" +"Last-Translator: Fabricio Maciel, 2024\n" "Language-Team: Portuguese (https://app.transifex.com/netbox-community/teams/178115/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -87,8 +87,8 @@ msgid "Your password has been changed successfully." msgstr "Sua senha foi alterada com sucesso." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planejado" @@ -99,7 +99,7 @@ msgstr "Provisionamento" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -109,7 +109,7 @@ msgid "Active" msgstr "Ativo" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Offline" @@ -122,7 +122,7 @@ msgstr "Em Desprovisionamento" msgid "Decommissioned" msgstr "Descomissionado" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Primário" @@ -181,8 +181,8 @@ msgstr "Grupo de sites (slug)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -347,7 +347,7 @@ msgstr "Grupo de circuitos (slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -359,21 +359,21 @@ msgstr "ASNs" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -414,7 +414,7 @@ msgstr "ASNs" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -481,9 +481,9 @@ msgid "Service ID" msgstr "ID do serviço" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -500,11 +500,11 @@ msgstr "Cor" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -549,11 +549,11 @@ msgstr "Conta do provedor" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -580,7 +580,7 @@ msgstr "Conta do provedor" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -605,10 +605,10 @@ msgstr "Status" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -712,11 +712,11 @@ msgstr "Velocidade da porta (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Velocidade de upstream (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Marcar como conectado" @@ -794,9 +794,9 @@ msgid "Provider network" msgstr "Rede do provedor" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -843,8 +843,8 @@ msgid "Contacts" msgstr "Contatos" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -867,7 +867,7 @@ msgid "Region" msgstr "Região" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -885,7 +885,7 @@ msgstr "Grupo de sites" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -920,16 +920,17 @@ msgstr "Conta" msgid "Term Side" msgstr "Lado da Terminação" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Atribuição" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -995,7 +996,7 @@ msgstr "ID única do circuito" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1134,7 +1135,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1245,7 +1246,7 @@ msgstr "redes dos provedores" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1382,7 +1383,7 @@ msgstr "Concluído" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Falhou" @@ -1529,8 +1530,8 @@ msgid "User name" msgstr "Nome de usuário" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1630,7 +1631,7 @@ msgid "Completed before" msgstr "Concluído antes" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1694,9 +1695,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Elevações de Rack" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Alimentação Elétrica" @@ -2230,11 +2231,11 @@ msgstr "Tarefa {id} foi interrompida." msgid "Failed to stop job {id}" msgstr "Falha ao interromper a tarefa {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Catálogo de plugins não pode ser carregado" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Plugin {name} não encontrado" @@ -2252,7 +2253,7 @@ msgid "Staging" msgstr "Em Preparação" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Em Descomissionamento" @@ -2312,7 +2313,7 @@ msgstr "Obsoleto" msgid "Millimeters" msgstr "Milímetros" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Polegadas" @@ -2324,8 +2325,8 @@ msgstr "Frente para trás" msgid "Rear to front" msgstr "Trás para frente" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2399,7 +2400,7 @@ msgstr "De baixo para cima" msgid "Top to bottom" msgstr "De cima para baixo" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Passivo" @@ -2427,8 +2428,8 @@ msgstr "Internacional/ITA" msgid "Proprietary" msgstr "Proprietário" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Outros" @@ -2441,22 +2442,22 @@ msgstr "ITA/Internacional" msgid "Physical" msgstr "Físico" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Virtual" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Wireless" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Interfaces virtuais" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2466,155 +2467,155 @@ msgstr "Interfaces virtuais" msgid "Bridge" msgstr "Bridge" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Link Aggregation (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (fixa)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modular)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (backplane)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Celular" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Serial" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Coaxial" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Empilhamento" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Half" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Full" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Automático" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Acesso" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Tagueada" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Tagueada (Todos)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Padrão IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "24V passivo (2 pares)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "24V passivo (4 pares)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "48V passivo (2 pares)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "48V passivo (4 pares)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Cabo Metálico" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Fibra Óptica" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fibra" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Conectado" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Quilômetros" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Metros" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Centímetros" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Milhas" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Pés" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Quilogramas" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramas" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Libras" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Onças" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Redundante" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Monofásico" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Trifásico" @@ -2847,7 +2848,7 @@ msgstr "Grupo de clusters (ID)" msgid "Device model (slug)" msgstr "Modelo do dispositivo (slug)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "É full-depth" @@ -2963,7 +2964,7 @@ msgstr "VLAN Designada" msgid "Assigned VID" msgstr "VLAN ID Designada " -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3124,27 +3125,27 @@ msgstr "" "Intervalos alfanuméricos são suportados. (Devem corresponder ao número de " "nomes que estão sendo criados.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Contato" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Telefone de Contato" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "E-mail de Contato" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Fuso horário" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3167,51 +3168,51 @@ msgstr "Fuso horário" msgid "Manufacturer" msgstr "Fabricante" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Formato físico" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Largura" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Altura (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Unidades descendentes" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Largura externa" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Profundidade externa" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Unidade externa" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Profundidade de montagem" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3232,13 +3233,13 @@ msgstr "Profundidade de montagem" msgid "Weight" msgstr "Peso" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Peso máximo" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3246,31 +3247,31 @@ msgstr "Peso máximo" msgid "Weight unit" msgstr "Unidade de peso" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Tipo de Rack" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Dimensões externas" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Dimensões" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numeração" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3310,21 +3311,21 @@ msgstr "Numeração" msgid "Role" msgstr "Função" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Número de Série" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Etiqueta de patrimônio" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3334,7 +3335,7 @@ msgstr "Etiqueta de patrimônio" msgid "Airflow" msgstr "Fluxo de Ar" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3354,7 +3355,7 @@ msgstr "Fluxo de Ar" msgid "Rack" msgstr "Rack" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3363,49 +3364,49 @@ msgstr "Rack" msgid "Hardware" msgstr "Hardware" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Plataforma padrão" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Part number" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Altura em U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Excluir da utilização" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Tipo de Dispositivo" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Tipo de Módulo" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Chassi" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Função da VM" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3418,19 +3419,19 @@ msgstr "Função da VM" msgid "Config template" msgstr "Modelo de configuração" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Tipo de dispositivo" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Função do dispositivo" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3444,8 +3445,28 @@ msgstr "Função do dispositivo" msgid "Platform" msgstr "Plataforma" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Cluster" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3502,22 +3523,27 @@ msgstr "Plataforma" msgid "Device" msgstr "Dispositivo" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Configuração" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Virtualização" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Tipo de módulo" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3529,82 +3555,82 @@ msgstr "Tipo de módulo" msgid "Label" msgstr "Rótulo" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Comprimento" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Unidade de comprimento" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Domínio" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Quadro de alimentação" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Tipo de Alimentação" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Fase" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Tensão" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Corrente" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Utilização máxima" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Consumo máximo" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Consumo máximo de energia (Watts)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Consumo alocado" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Consumo de energia alocado (Watts)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Porta de alimentação" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Ramal de alimentação" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Somente gerenciamento" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3612,7 +3638,7 @@ msgstr "Somente gerenciamento" msgid "PoE mode" msgstr "Modo de Operação" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3620,12 +3646,12 @@ msgstr "Modo de Operação" msgid "PoE type" msgstr "Tipo de PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Função do Wireless" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3635,16 +3661,16 @@ msgstr "Função do Wireless" msgid "Module" msgstr "Módulo" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Contextos de dispositivos virtuais" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3653,7 +3679,7 @@ msgstr "Contextos de dispositivos virtuais" msgid "Speed" msgstr "Velocidade" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3664,36 +3690,44 @@ msgstr "Velocidade" msgid "Mode" msgstr "Modo" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Grupo de VLANs" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN Não Tagueada" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "VLANs Tagueadas" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "Adicionar VLANs tagueadas" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "Remover VLANs tagueadas" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Grupo da Rede Wireless" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Redes Wireless" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3701,33 +3735,37 @@ msgstr "Redes Wireless" msgid "Addressing" msgstr "Endereçamento" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operação" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Interfaces Relacionadas" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Comutação 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "Adicionar/Remover" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "O modo de interface deve ser especificado para atribuir VLANs" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Uma interface de acesso não pode ter VLANs tagueadas." @@ -3868,26 +3906,6 @@ msgstr "Plataforma designada" msgid "Virtual chassis" msgstr "Chassi virtual" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Cluster" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Cluster de virtualização" @@ -6622,32 +6640,32 @@ msgstr "Ocorreu um erro ao renderizar o modelo: {error}" msgid "Virtual Machines" msgstr "Máquinas Virtuais" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Dispositivo instalado {device} no compartimento {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Dispositivo {device} removido do compartimento {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Filhos" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Membro {device} adicionado" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "" "Não é possível remover o dispositivo principal {device} do chassi virtual." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Removido {device} do chassi virtual {chassis}" @@ -7595,19 +7613,19 @@ msgstr "Programe a execução do script para um horário definido" msgid "Interval at which this script is re-run (in minutes)" msgstr "Intervalo no qual este script é executado novamente (em minutos)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "As alterações no banco de dados foram revertidas automaticamente." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Script abortado com erro: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Ocorreu uma exceção: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "As alterações do banco de dados foram revertidas devido a um erro." @@ -8931,7 +8949,7 @@ msgstr "Grupo de VLANs" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9188,7 +9206,7 @@ msgstr "Associado a uma interface" msgid "DNS Name" msgstr "Nome DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9198,7 +9216,7 @@ msgstr "VLANs" msgid "Contains VLAN ID" msgstr "Contém ID de VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "ID da VLAN" @@ -9658,40 +9676,48 @@ msgstr "Não é possível definir scope_type sem scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Não é possível definir scope_id sem scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Os intervalos não podem se sobrepor." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"A VLAN ID máxima do filho deve ser maior ou igual a VLAN ID mínima do filho." -" ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "O site específico ao qual esta VLAN está associada (se houver)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Grupo de VLANs (opcional)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "ID numérica da VLAN (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Status operacional desta VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Função principal desta VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9700,7 +9726,7 @@ msgstr "" "A VLAN está atribuída ao grupo {group} (escopo: {scope}); não pode ser " "associada ao site {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VLAN ID devem estar nas faixas {ranges} para VLANs no grupo {group}" @@ -10446,10 +10472,6 @@ msgstr "Políticas de IPsec" msgid "IPSec Profiles" msgstr "Perfis de IPsec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Virtualização" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10852,19 +10874,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Linha {i}: Objeto com ID {id} não existe" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Nenhum {object_type} foi/foram selecionado(s)." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Renomeado(s) {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Excluído(s) {count} {object_type}" @@ -10897,7 +10919,7 @@ msgstr "Sincronizado(s) {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} deve implementar get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12756,7 +12778,7 @@ msgid "You do not have permission to run scripts" msgstr "Você não tem permissão para executar scripts" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Executar Script" @@ -12768,27 +12790,32 @@ msgstr "Erro ao carregar o script" msgid "Script no longer exists in the source file." msgstr "O script não existe mais no arquivo de origem." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Última Execução" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "O script não está mais presente no arquivo de origem" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Nunca" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Execute Novamente" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "Não foi possível carregar os scripts do módulo %(module)s" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Nenhum Script Encontrado" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14639,13 +14666,13 @@ msgid "Memory (MB)" msgstr "Memória (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disco (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Tamanho (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/ru/LC_MESSAGES/django.mo b/netbox/translations/ru/LC_MESSAGES/django.mo index b1e1f8921..785b3f6d5 100644 Binary files a/netbox/translations/ru/LC_MESSAGES/django.mo and b/netbox/translations/ru/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/ru/LC_MESSAGES/django.po b/netbox/translations/ru/LC_MESSAGES/django.po index 3c4d40f08..4016b82d4 100644 --- a/netbox/translations/ru/LC_MESSAGES/django.po +++ b/netbox/translations/ru/LC_MESSAGES/django.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Russian (https://app.transifex.com/netbox-community/teams/178115/ru/)\n" @@ -90,8 +90,8 @@ msgid "Your password has been changed successfully." msgstr "Ваш пароль успешно изменен." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Запланировано" @@ -102,7 +102,7 @@ msgstr "Эксплутация" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -112,7 +112,7 @@ msgid "Active" msgstr "Активный" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Оффлайн" @@ -125,7 +125,7 @@ msgstr "Вывод из эксплуатации" msgid "Decommissioned" msgstr "Списан" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Основной" @@ -184,8 +184,8 @@ msgstr "Группа сайтов (подстрока)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -350,7 +350,7 @@ msgstr "Группа каналов связи (подстрока)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -362,21 +362,21 @@ msgstr "ASN" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -417,7 +417,7 @@ msgstr "ASN" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -484,9 +484,9 @@ msgid "Service ID" msgstr "Идентификатор Службы" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -503,11 +503,11 @@ msgstr "Цвет" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -552,11 +552,11 @@ msgstr "Аккаунт провайдера" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -583,7 +583,7 @@ msgstr "Аккаунт провайдера" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -608,10 +608,10 @@ msgstr "Статус" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -715,11 +715,11 @@ msgstr "Скорость порта (Кбит/с)" msgid "Upstream speed (Kbps)" msgstr "Скорость восходящего потока (Кбит/с)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Пометить подключенным" @@ -797,9 +797,9 @@ msgid "Provider network" msgstr "Сеть провайдера" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -846,8 +846,8 @@ msgid "Contacts" msgstr "Контакты" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -870,7 +870,7 @@ msgid "Region" msgstr "Регион" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -888,7 +888,7 @@ msgstr "Группа сайтов" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -923,16 +923,17 @@ msgstr "Аккаунт" msgid "Term Side" msgstr "Терминология" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Задание" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -998,7 +999,7 @@ msgstr "Уникальный ID канала связи" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1137,7 +1138,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1248,7 +1249,7 @@ msgstr "сети провайдера" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1386,7 +1387,7 @@ msgstr "Завершено" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Неисправно" @@ -1533,8 +1534,8 @@ msgid "User name" msgstr "Имя пользователя" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1634,7 +1635,7 @@ msgid "Completed before" msgstr "Завершено до" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1695,9 +1696,9 @@ msgstr "Необходимо загрузить файл или выбрать msgid "Rack Elevations" msgstr "Фасады стоек" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Мощность" @@ -2231,11 +2232,11 @@ msgstr "Задача {id} остановлена." msgid "Failed to stop job {id}" msgstr "Не удалось остановить задачу {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Не удалось загрузить каталог плагинов" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Плагин {name} не найден" @@ -2253,7 +2254,7 @@ msgid "Staging" msgstr "Подготовка к развертыванию" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Вывод из эксплуатации" @@ -2313,7 +2314,7 @@ msgstr "Выведенный(-ая) из использования" msgid "Millimeters" msgstr "Миллиметры" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Дюймы" @@ -2325,8 +2326,8 @@ msgstr "Спереди назад" msgid "Rear to front" msgstr "Сзади вперед" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2400,7 +2401,7 @@ msgstr "Снизу вверх" msgid "Top to bottom" msgstr "Сверху вниз" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Пассивный" @@ -2428,8 +2429,8 @@ msgstr "ITA/Международный" msgid "Proprietary" msgstr "Проприетарный" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Другой" @@ -2442,22 +2443,22 @@ msgstr "ITA/Международный" msgid "Physical" msgstr "Физический" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Виртуальный" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Беспроводной" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Виртуальные интерфейсы" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2467,155 +2468,155 @@ msgstr "Виртуальные интерфейсы" msgid "Bridge" msgstr "Мост" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Группа агрегации линков (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (фиксированный)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (модульный)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (объединительная плата)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Сотовая связь" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Серийный" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Коаксиальный" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Стекирование" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Полу" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Полный" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Авто" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Доступ" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Тегированный" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Тегированный (все)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Стандарт IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Пассивный режим 24 В (2 пары)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Пассивное напряжение 24 В (4 пары)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Пассивное напряжение 48 В (2 пары)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Пассивное напряжение 48 В (4 пары)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Медь" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Оптоволоконное" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Волокно" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Подключено" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Километры" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Метры" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Сантиметры" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Мили" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Футы" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Килограммы" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Граммы" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Фунты" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Унции" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Резервный" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Однофазный" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Трехфазный" @@ -2848,7 +2849,7 @@ msgstr "Кластерная группа (ID)" msgid "Device model (slug)" msgstr "Модель устройства (подстрока)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Полная глубина" @@ -2964,7 +2965,7 @@ msgstr "Назначенная VLAN" msgid "Assigned VID" msgstr "Назначенный VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3125,27 +3126,27 @@ msgstr "" "Поддерживаются алфавитно-цифровые диапазоны. (Должно совпадать с количеством" " создаваемых имен.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Имя контактного лица" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Контактный телефон" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Контактный адрес электронной почты" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Часовой пояс" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3168,51 +3169,51 @@ msgstr "Часовой пояс" msgid "Manufacturer" msgstr "Производитель" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Форм-фактор" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Ширина" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Высота (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Единицы по убыванию" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Наружная ширина" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Внешняя глубина" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Внешний блок" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Глубина крепления" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3233,13 +3234,13 @@ msgstr "Глубина крепления" msgid "Weight" msgstr "Вес" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Максимальный вес" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3247,31 +3248,31 @@ msgstr "Максимальный вес" msgid "Weight unit" msgstr "Единица веса" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Тип стойки" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Внешние размеры" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Габариты" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Нумерация" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3311,21 +3312,21 @@ msgstr "Нумерация" msgid "Role" msgstr "Роль" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Серийный номер" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Инвентарный номер" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3335,7 +3336,7 @@ msgstr "Инвентарный номер" msgid "Airflow" msgstr "Воздушный поток" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3355,7 +3356,7 @@ msgstr "Воздушный поток" msgid "Rack" msgstr "Стойка" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3364,49 +3365,49 @@ msgstr "Стойка" msgid "Hardware" msgstr "Аппаратное обеспечение" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Платформа по умолчанию" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Номер детали" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Высота U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Исключить из использования" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Тип устройства" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Тип модуля" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Шасси" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Роль виртуальной машины" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3419,19 +3420,19 @@ msgstr "Роль виртуальной машины" msgid "Config template" msgstr "Шаблон конфигурации" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Тип устройства" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Роль устройства" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3445,8 +3446,28 @@ msgstr "Роль устройства" msgid "Platform" msgstr "Платформа" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Кластер" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3503,22 +3524,27 @@ msgstr "Платформа" msgid "Device" msgstr "Устройство" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Конфигурация" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Виртуализация" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Тип модуля" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3530,82 +3556,82 @@ msgstr "Тип модуля" msgid "Label" msgstr "Лейбл" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Длина" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Единица длины" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Домен" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Панель питания" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Снабжение" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Фаза" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Напряжение" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Сила тока" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Максимальное использование" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Максимальное потребление" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Максимальная потребляемая мощность (Вт)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Выделенная мощность" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Распределенная потребляемая мощность (Вт)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Порт питания" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Фаза электропитания" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Только управление" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3613,7 +3639,7 @@ msgstr "Только управление" msgid "PoE mode" msgstr "Режим PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3621,12 +3647,12 @@ msgstr "Режим PoE" msgid "PoE type" msgstr "Тип PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Роль беспроводной связи" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3636,16 +3662,16 @@ msgstr "Роль беспроводной связи" msgid "Module" msgstr "Модуль" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Виртуальные контексты" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3654,7 +3680,7 @@ msgstr "Виртуальные контексты" msgid "Speed" msgstr "Скорость" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3665,36 +3691,44 @@ msgstr "Скорость" msgid "Mode" msgstr "Режим" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Группа VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN без тегов" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "VLAN с тегами" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Беспроводная группа LAN" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Беспроводные LANы" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3702,33 +3736,37 @@ msgstr "Беспроводные LANы" msgid "Addressing" msgstr "Адресация" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Операция" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Связанные интерфейсы" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Коммутация 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "Для назначения VLAN необходимо указать режим интерфейса" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Интерфейсу доступа нельзя назначать VLAN с тегами." @@ -3869,26 +3907,6 @@ msgstr "Назначенная платформа" msgid "Virtual chassis" msgstr "Виртуальное шасси" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Кластер" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Кластер виртуализации" @@ -6610,31 +6628,31 @@ msgstr "Во время рендеринга шаблона произошла msgid "Virtual Machines" msgstr "Виртуальные машины" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Установлено устройство {device} в отсек {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Удалено устройство {device} из отсека {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Потомки" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Добавлен участник {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Невозможно удалить главное устройство {device} из виртуального шасси." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "{device} удалено из виртуального шасси {chassis}" @@ -7582,19 +7600,19 @@ msgstr "Запланируйте выполнение скрипта на зад msgid "Interval at which this script is re-run (in minutes)" msgstr "Интервал повторного запуска этого скрипта (в минутах)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Изменения в базе данных были автоматически отменены." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Скрипт прерван с ошибкой: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Возникло исключение: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Изменения в базе данных отменены из-за ошибки." @@ -8911,7 +8929,7 @@ msgstr "VLAN группа" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9168,7 +9186,7 @@ msgstr "Назначено интерфейсу" msgid "DNS Name" msgstr "DNS-имя" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9178,7 +9196,7 @@ msgstr "VLAN" msgid "Contains VLAN ID" msgstr "Содержит идентификатор VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN ID" @@ -9634,40 +9652,48 @@ msgstr "Невозможно установить scope_type без scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Невозможно установить scope_id без scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Диапазоны не могут перекрываться." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Максимальное количество детских VID должно быть больше или равно " -"минимальному детскому VID ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Конкретный сайт, которому назначена эта VLAN (если есть)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Группа VLAN (опционально)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Цифровой VLAN ID (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Рабочее состояние этой VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Основная функция этой VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9676,7 +9702,7 @@ msgstr "" "VLAN назначена группе {group} (область применения: {scope}); также не может " "быть присвоено сайту {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "" @@ -10426,10 +10452,6 @@ msgstr "Политики IPsec" msgid "IPSec Profiles" msgstr "Профили IPsec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Виртуализация" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10835,19 +10857,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Ряд {i}: Объект с идентификатором {id} не существует" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "{object_type} не были выбраны." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Переименован(-о) {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Удален(-о) {count} {object_type}" @@ -10879,7 +10901,7 @@ msgstr "Синхронизирован(-о) {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} должен реализовать get_children ()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12738,7 +12760,7 @@ msgid "You do not have permission to run scripts" msgstr "У вас нет разрешения на запуск скриптов" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Запустить скрипт" @@ -12750,27 +12772,32 @@ msgstr "Ошибка при загрузке скрипта" msgid "Script no longer exists in the source file." msgstr "Скрипт больше не существует в исходном файле." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Последний запуск" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Скрипт больше не присутствует в исходном файле" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Никогда" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Повторить" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Скрипты не найдены" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14623,13 +14650,13 @@ msgid "Memory (MB)" msgstr "Память (МБ)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Диск (ГБ)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Размер (ГБ)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/tr/LC_MESSAGES/django.mo b/netbox/translations/tr/LC_MESSAGES/django.mo index 9117323f5..998a28451 100644 Binary files a/netbox/translations/tr/LC_MESSAGES/django.mo and b/netbox/translations/tr/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/tr/LC_MESSAGES/django.po b/netbox/translations/tr/LC_MESSAGES/django.po index aec1ef71e..40c255c45 100644 --- a/netbox/translations/tr/LC_MESSAGES/django.po +++ b/netbox/translations/tr/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Turkish (https://app.transifex.com/netbox-community/teams/178115/tr/)\n" @@ -86,8 +86,8 @@ msgid "Your password has been changed successfully." msgstr "Şifreniz başarıyla değiştirildi." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Planlanan" @@ -98,7 +98,7 @@ msgstr "Tedarik" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -108,7 +108,7 @@ msgid "Active" msgstr "Aktif" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Çevrim dışı" @@ -121,7 +121,7 @@ msgstr "Hazırlıktan Kaldırma" msgid "Decommissioned" msgstr "Hizmet dışı bırakıldı" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Birincil" @@ -180,8 +180,8 @@ msgstr "Site grubu (kısa ad)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -346,7 +346,7 @@ msgstr "Devre grubu (sümüklü böcek)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -358,21 +358,21 @@ msgstr "ASN'ler" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -413,7 +413,7 @@ msgstr "ASN'ler" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -480,9 +480,9 @@ msgid "Service ID" msgstr "Servis ID" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -499,11 +499,11 @@ msgstr "Renk" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -548,11 +548,11 @@ msgstr "Sağlayıcı hesabı" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -579,7 +579,7 @@ msgstr "Sağlayıcı hesabı" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -604,10 +604,10 @@ msgstr "Durum" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -711,11 +711,11 @@ msgstr "Bağlantı noktası hızı (Kbps)" msgid "Upstream speed (Kbps)" msgstr "Yukarı akış hızı (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "Bağlı olarak işaretle" @@ -793,9 +793,9 @@ msgid "Provider network" msgstr "Sağlayıcı ağı" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -842,8 +842,8 @@ msgid "Contacts" msgstr "İletişim" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -866,7 +866,7 @@ msgid "Region" msgstr "Bölge" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -884,7 +884,7 @@ msgstr "Site grubu" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -919,16 +919,17 @@ msgstr "Hesap" msgid "Term Side" msgstr "Dönem Tarafı" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Ödev" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -994,7 +995,7 @@ msgstr "Benzersiz devre ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1130,7 +1131,7 @@ msgstr "Devre sonlandırma hem siteye hem de sağlayıcı ağına bağlanamaz." #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1241,7 +1242,7 @@ msgstr "sağlayıcı ağları" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1378,7 +1379,7 @@ msgstr "Tamamlandı" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Başarısız" @@ -1525,8 +1526,8 @@ msgid "User name" msgstr "Kullanıcı adı" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1626,7 +1627,7 @@ msgid "Completed before" msgstr "Daha önce tamamlandı" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1688,9 +1689,9 @@ msgstr "" msgid "Rack Elevations" msgstr "Raf Yükseltmeleri" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Güç" @@ -2221,11 +2222,11 @@ msgstr "İş {id} durduruldu." msgid "Failed to stop job {id}" msgstr "İş durdurulamadı {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Eklentiler kataloğu yüklenemedi" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Eklenti {name} bulunamadı" @@ -2243,7 +2244,7 @@ msgid "Staging" msgstr "Sahneleme" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Hizmetten çıkarma" @@ -2303,7 +2304,7 @@ msgstr "Kullanımdan kaldırıldı" msgid "Millimeters" msgstr "Milimetre" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "İnç" @@ -2315,8 +2316,8 @@ msgstr "Önden arkaya" msgid "Rear to front" msgstr "Arkadan öne" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2390,7 +2391,7 @@ msgstr "Aşağıdan yukarıya" msgid "Top to bottom" msgstr "Yukarıdan aşağıya" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Pasif" @@ -2418,8 +2419,8 @@ msgstr "Uluslararası/ITA" msgid "Proprietary" msgstr "Tescilli" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Diğer" @@ -2432,22 +2433,22 @@ msgstr "ITA/Uluslararası" msgid "Physical" msgstr "Fiziksel" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Sanal" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Kablosuz" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Sanal arayüzler" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2457,155 +2458,155 @@ msgstr "Sanal arayüzler" msgid "Bridge" msgstr "Köprü" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Bağlantı Toplama Grubu (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (sabit)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (modüler)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (arka panel)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Hücresel" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Seri" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Koaksiyel" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "İstifleme" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Yarım" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Dolu" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Oto" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Erişim" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Etiketlenmiş" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Etiketlenmiş (Tümü)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE Standardı" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Pasif 24V (2 çift)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Pasif 24V (4 çift)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Pasif 48V (2 çift)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Pasif 48V (4 çift)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Bakır" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Fiber Optik" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Fiber" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Bağlı" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Kilometre" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Sayaçlar" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Santimetre" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Mil" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Feet" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Kilogram" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Gramlar" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Pound'lar" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "ons" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Yedekli" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Tek fazlı" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Üç fazlı" @@ -2838,7 +2839,7 @@ msgstr "Küme grubu (ID)" msgid "Device model (slug)" msgstr "Cihaz modeli (kısa ad)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Tam derinlik mi" @@ -2954,7 +2955,7 @@ msgstr "Atanmış VLAN" msgid "Assigned VID" msgstr "Atanmış VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3115,27 +3116,27 @@ msgstr "" "Alfasayısal aralıklar desteklenir. (Oluşturulan isim sayısıyla " "eşleşmelidir.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "İrtibat Kişisi Adı" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "İletişim telefonu" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "İletişim E-posta" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Saat dilimi" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3158,51 +3159,51 @@ msgstr "Saat dilimi" msgid "Manufacturer" msgstr "Üretici" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Form faktörü" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Genişlik" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Yükseklik (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Azalan birimler" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Dış genişlik" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Dış derinlik" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Dış ünite" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Montaj derinliği" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3223,13 +3224,13 @@ msgstr "Montaj derinliği" msgid "Weight" msgstr "Ağırlığı" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Maksimum ağırlık" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3237,31 +3238,31 @@ msgstr "Maksimum ağırlık" msgid "Weight unit" msgstr "Ağırlık birimi" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Raf Tipi" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Dış Ölçüler" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Ölçüler" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Numaralandırma" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3301,21 +3302,21 @@ msgstr "Numaralandırma" msgid "Role" msgstr "Rol" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Seri Numarası" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Varlık etiketi" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3325,7 +3326,7 @@ msgstr "Varlık etiketi" msgid "Airflow" msgstr "Hava akışı" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3345,7 +3346,7 @@ msgstr "Hava akışı" msgid "Rack" msgstr "Raf" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3354,49 +3355,49 @@ msgstr "Raf" msgid "Hardware" msgstr "Donanım" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Varsayılan platform" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Parça numarası" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "U yüksekliği" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Kullanımdan hariç tut" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Cihaz Türü" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Modül Türü" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Şasi" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VM rolü" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3409,19 +3410,19 @@ msgstr "VM rolü" msgid "Config template" msgstr "Yapılandırma şablonu" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Cihaz tipi" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Cihaz rolü" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3435,8 +3436,28 @@ msgstr "Cihaz rolü" msgid "Platform" msgstr "Platform" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Küme" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3493,22 +3514,27 @@ msgstr "Platform" msgid "Device" msgstr "Cihaz" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Yapılandırma" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Sanallaştırma" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Modül tipi" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3520,82 +3546,82 @@ msgstr "Modül tipi" msgid "Label" msgstr "etiket" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Uzunluk" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Uzunluk birimi" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Alan adı" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Güç paneli" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Tedarik" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Faz" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Gerilim" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Amper" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Maksimum kullanım" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Maksimum çekiliş" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Maksimum güç çekimi (watt)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Tahsis edilen çekiliş" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Tahsis edilen güç çekimi (watt)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Güç bağlantı noktası" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Besleme bacağı" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Yalnızca yönetim" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3603,7 +3629,7 @@ msgstr "Yalnızca yönetim" msgid "PoE mode" msgstr "PoE modu" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3611,12 +3637,12 @@ msgstr "PoE modu" msgid "PoE type" msgstr "PoE tipi" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Kablosuz rolü" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3626,16 +3652,16 @@ msgstr "Kablosuz rolü" msgid "Module" msgstr "Modül" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "GECİKME" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Sanal cihaz bağlamları" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3644,7 +3670,7 @@ msgstr "Sanal cihaz bağlamları" msgid "Speed" msgstr "Hız" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3655,36 +3681,44 @@ msgstr "Hız" msgid "Mode" msgstr "Modu" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN grubu" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "Etiketsiz VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "Etiketli VLAN'lar" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Kablosuz LAN grubu" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Kablosuz LAN'lar" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3692,33 +3726,37 @@ msgstr "Kablosuz LAN'lar" msgid "Addressing" msgstr "Adresleme" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Operasyon" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "İlgili Arayüzler" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q Anahtarlama" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "VLAN'ları atamak için arayüz modu belirtilmelidir" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Bir erişim arabirimi VLAN'ları etiketlemiş olamaz." @@ -3859,26 +3897,6 @@ msgstr "Atanan platform" msgid "Virtual chassis" msgstr "Sanal şasi" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Küme" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Sanallaştırma kümesi" @@ -6553,31 +6571,31 @@ msgstr "Şablon oluşturulurken bir hata oluştu: {error}" msgid "Virtual Machines" msgstr "Sanal Makineler" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Yüklü cihaz {device} körfezde {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Kaldırılan cihaz {device} körfezden {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Çocuklar" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Eklenen üye {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Ana aygıt kaldırılamıyor {device} sanal kasadan." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Kaldırıldı {device} sanal kasadan {chassis}" @@ -7519,19 +7537,19 @@ msgstr "Komut dosyasının yürütülmesini belirli bir zamana planlayın" msgid "Interval at which this script is re-run (in minutes)" msgstr "Bu komut dosyasının yeniden çalıştırıldığı aralık (dakika cinsinden)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Veritabanı değişiklikleri otomatik olarak geri alındı." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Komut dosyası hatayla iptal edildi: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Bir istisna oluştu: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Veritabanı değişiklikleri hata nedeniyle geri alındı." @@ -8845,7 +8863,7 @@ msgstr "VLAN Grubu" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -9100,7 +9118,7 @@ msgstr "Bir arayüze atandı" msgid "DNS Name" msgstr "DNS Adı" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -9110,7 +9128,7 @@ msgstr "VLAN'lar" msgid "Contains VLAN ID" msgstr "VLAN Kimliği içerir" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN KİMLİĞİ" @@ -9560,40 +9578,48 @@ msgstr "scope_id olmadan scope_type ayarlanamıyor." msgid "Cannot set scope_id without scope_type." msgstr "scope_type olmadan scope_id ayarlanamıyor." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Aralıklar üst üste gelemez." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Maksimum çocuk VID, minimum çocuk VID'den büyük veya ona eşit olmalıdır " -"({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Bu VLAN'ın atandığı belirli site (varsa)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN grubu (isteğe bağlı)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Sayısal VLAN Kimliği (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Bu VLAN'ın operasyonel durumu" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Bu VLAN'ın birincil işlevi" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9602,7 +9628,7 @@ msgstr "" "VLAN {group} adlı gruba (kapsam: {scope}) atandığı için; {site} adlı siteye " "de atanamaz ." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID aralıklarda olmalıdır {ranges} gruptaki VLAN'lar için {group}" @@ -10348,10 +10374,6 @@ msgstr "IPsec İlkeleri" msgid "IPSec Profiles" msgstr "IPsec Profilleri" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Sanallaştırma" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10756,19 +10778,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Satır {i}: Kimliği olan nesne {id} mevcut değil" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Hayır {object_type} seçildi." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Yeniden adlandırıldı {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Silinmiş {count} {object_type}" @@ -10800,7 +10822,7 @@ msgstr "Senkronize {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name} get_children () uygulamasını uygulamalıdır" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12659,7 +12681,7 @@ msgid "You do not have permission to run scripts" msgstr "Komut dosyalarını çalıştırma izniniz yok" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Komut Dosyasını Çalıştır" @@ -12671,27 +12693,32 @@ msgstr "Komut dosyası yüklenirken hata oluştu" msgid "Script no longer exists in the source file." msgstr "Kaynak dosyada komut dosyası artık mevcut değil." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Son Koşu" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Komut dosyası artık kaynak dosyada mevcut değil" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Asla" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Tekrar koş" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Komut Dosyası Bulunamadı" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14527,13 +14554,13 @@ msgid "Memory (MB)" msgstr "Bellek (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Disk (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Boyut (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/translations/uk/LC_MESSAGES/django.mo b/netbox/translations/uk/LC_MESSAGES/django.mo index b5c8a4fe9..eefdca659 100644 Binary files a/netbox/translations/uk/LC_MESSAGES/django.mo and b/netbox/translations/uk/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/uk/LC_MESSAGES/django.po b/netbox/translations/uk/LC_MESSAGES/django.po index de7d910b3..08def4548 100644 --- a/netbox/translations/uk/LC_MESSAGES/django.po +++ b/netbox/translations/uk/LC_MESSAGES/django.po @@ -5,17 +5,17 @@ # # Translators: # Volodymyr Pidgornyi, 2024 -# Jeremy Stretch, 2024 # Vladyslav V. Prodan, 2024 +# Jeremy Stretch, 2024 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" -"Last-Translator: Vladyslav V. Prodan, 2024\n" +"Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Ukrainian (https://app.transifex.com/netbox-community/teams/178115/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -85,8 +85,8 @@ msgid "Your password has been changed successfully." msgstr "Ваш пароль успішно змінено." #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "Заплановано" @@ -97,7 +97,7 @@ msgstr "Забезпечення" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -107,7 +107,7 @@ msgid "Active" msgstr "Активний" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "Офлайн" @@ -120,7 +120,7 @@ msgstr "Зняття з експлуатації" msgid "Decommissioned" msgstr "Виведені з експлуатації" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "Первинний" @@ -179,8 +179,8 @@ msgstr "Група тех. майданчиків (скорочення)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -337,15 +337,15 @@ msgstr "Канал зв'язку (ідентифікатор вмісту)" #: circuits/filtersets.py:345 msgid "Circuit group (ID)" -msgstr "Группа каналів зв'язку (ідентифікатор)" +msgstr "Група каналів зв'язку (ідентифікатор)" #: circuits/filtersets.py:351 msgid "Circuit group (slug)" -msgstr "Группа каналів зв'язку (скорочення)" +msgstr "Група каналів зв'язку (скорочення)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -357,21 +357,21 @@ msgstr "ASNs" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -412,7 +412,7 @@ msgstr "ASNs" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -479,9 +479,9 @@ msgid "Service ID" msgstr "Ідентифікатор служби" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -498,11 +498,11 @@ msgstr "Колір" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -547,11 +547,11 @@ msgstr "Обліковий запис постачальника" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -578,7 +578,7 @@ msgstr "Обліковий запис постачальника" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -603,10 +603,10 @@ msgstr "Статус" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -670,7 +670,7 @@ msgstr "Дата припинення дії" #: circuits/forms/bulk_edit.py:158 circuits/forms/filtersets.py:186 msgid "Commit rate (Kbps)" -msgstr "Гарантована мінімальна швідкість (Кбіт/с)" +msgstr "Гарантована мінімальна швидкість (Кбіт/с)" #: circuits/forms/bulk_edit.py:173 circuits/forms/model_forms.py:112 msgid "Service Parameters" @@ -700,7 +700,7 @@ msgstr "Оренда" #: templates/circuits/inc/circuit_termination_fields.html:62 #: templates/circuits/providernetwork.html:17 msgid "Provider Network" -msgstr "Мережа провайдерів" +msgstr "Мережа провайдера" #: circuits/forms/bulk_edit.py:199 msgid "Port speed (Kbps)" @@ -710,13 +710,13 @@ msgstr "Швидкість порту (Кбіт/с)" msgid "Upstream speed (Kbps)" msgstr "Швидкість висхідного потоку (Кбіт/с)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" -msgstr "Позначка з'єднана" +msgstr "Позначити з'єднаним" #: circuits/forms/bulk_edit.py:219 circuits/forms/model_forms.py:157 #: templates/circuits/inc/circuit_termination_fields.html:54 @@ -727,7 +727,7 @@ msgstr "Кінець каналу зв'язку" #: circuits/forms/bulk_edit.py:221 circuits/forms/model_forms.py:159 msgid "Termination Details" -msgstr "Деталі припинення" +msgstr "Деталі кінця" #: circuits/forms/bulk_edit.py:251 circuits/forms/filtersets.py:268 #: circuits/tables/circuits.py:168 dcim/forms/model_forms.py:551 @@ -746,7 +746,7 @@ msgstr "Призначений провайдер" #: circuits/forms/bulk_import.py:83 msgid "Assigned provider account" -msgstr "Призначений обліковий запис постачальника" +msgstr "Призначений обліковий запис провайдера" #: circuits/forms/bulk_import.py:90 msgid "Type of circuit" @@ -784,17 +784,17 @@ msgstr "Призначений орендар" #: templates/dcim/cable.html:68 templates/dcim/cable.html:72 #: vpn/forms/bulk_import.py:100 vpn/forms/filtersets.py:77 msgid "Termination" -msgstr "Припинення" +msgstr "Кінець" #: circuits/forms/bulk_import.py:130 circuits/forms/filtersets.py:147 #: circuits/forms/filtersets.py:227 circuits/forms/model_forms.py:144 msgid "Provider network" -msgstr "Мережа провайдерів" +msgstr "Мережа провайдера" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -841,8 +841,8 @@ msgid "Contacts" msgstr "Контакти" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -865,7 +865,7 @@ msgid "Region" msgstr "Регіон" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -883,7 +883,7 @@ msgstr "Група тех. майданчиків" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -912,22 +912,23 @@ msgstr "Атрибути" #: circuits/tables/providers.py:66 templates/circuits/circuit.html:22 #: templates/circuits/provideraccount.html:24 msgid "Account" -msgstr "Рахунок" +msgstr "Обліковий запис" #: circuits/forms/filtersets.py:217 msgid "Term Side" -msgstr "Сторона терміну" +msgstr "Сторона завершення" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "Призначення" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -961,7 +962,7 @@ msgstr "Група" #: circuits/forms/model_forms.py:182 templates/circuits/circuitgroup.html:25 msgid "Circuit Group" -msgstr "Група каналу зв'язку" +msgstr "Група каналів зв'язку" #: circuits/models/circuits.py:27 dcim/models/cables.py:67 #: dcim/models/device_component_templates.py:517 @@ -982,7 +983,7 @@ msgstr "типи каналів зв'язку" #: circuits/models/circuits.py:48 msgid "circuit ID" -msgstr "iдентифікатор каналу зв'язку" +msgstr "ідентифікатор каналу зв'язку" #: circuits/models/circuits.py:49 msgid "Unique circuit ID" @@ -993,7 +994,7 @@ msgstr "Унікальний ідентифікатор каналу зв'язк #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1010,11 +1011,11 @@ msgstr "припинється" #: circuits/models/circuits.py:94 msgid "commit rate (Kbps)" -msgstr "гарантована мінімальна швідкість (Кбіт/с)" +msgstr "гарантована швидкість (Кбіт/с)" #: circuits/models/circuits.py:95 msgid "Committed rate" -msgstr "Гарантирована швідкість" +msgstr "Гарантована швидкість" #: circuits/models/circuits.py:137 msgid "circuit" @@ -1026,7 +1027,7 @@ msgstr "канали зв'язку" #: circuits/models/circuits.py:170 msgid "circuit group" -msgstr "група каналу зв'язку" +msgstr "група каналів зв'язку" #: circuits/models/circuits.py:171 msgid "circuit groups" @@ -1047,7 +1048,7 @@ msgstr "Призначення групи каналів зв'язку" #: circuits/models/circuits.py:240 msgid "termination" -msgstr "припинення" +msgstr "кінець" #: circuits/models/circuits.py:257 msgid "port speed (Kbps)" @@ -1063,7 +1064,8 @@ msgstr "швидкість висхідного потоку (Кбіт/с)" #: circuits/models/circuits.py:266 msgid "Upstream speed, if different from port speed" -msgstr "Швидкість висхідного потоку, якщо відрізняється від швидкості порту" +msgstr "" +"Швидкість висхідного потоку, якщо вона відрізняється від швидкості порту" #: circuits/models/circuits.py:271 msgid "cross-connect ID" @@ -1132,7 +1134,7 @@ msgstr "" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1144,11 +1146,11 @@ msgstr "" #: vpn/models/crypto.py:221 vpn/models/l2vpn.py:22 vpn/models/tunnels.py:35 #: wireless/models.py:51 msgid "name" -msgstr "найменування" +msgstr "назва" #: circuits/models/providers.py:25 msgid "Full name of the provider" -msgstr "Повне найменування провайдера" +msgstr "Повна назва провайдера" #: circuits/models/providers.py:28 dcim/models/devices.py:86 #: dcim/models/racks.py:137 dcim/models/sites.py:149 @@ -1169,7 +1171,7 @@ msgstr "провайдери" #: circuits/models/providers.py:63 msgid "account ID" -msgstr "iдентифікатор рахунку" +msgstr "ідентифікатор облікового запису" #: circuits/models/providers.py:86 msgid "provider account" @@ -1177,11 +1179,11 @@ msgstr "обліковий запис провайдера" #: circuits/models/providers.py:87 msgid "provider accounts" -msgstr "акаунти провайдера" +msgstr "облікові записи провайдера" #: circuits/models/providers.py:115 msgid "service ID" -msgstr "iдентифікатор послуги" +msgstr "ідентифікатор послуги" #: circuits/models/providers.py:126 msgid "provider network" @@ -1189,7 +1191,7 @@ msgstr "мережа провайдера" #: circuits/models/providers.py:127 msgid "provider networks" -msgstr "мережі провайдерів" +msgstr "мережі провайдера" #: circuits/tables/circuits.py:32 circuits/tables/circuits.py:132 #: circuits/tables/providers.py:18 circuits/tables/providers.py:69 @@ -1243,7 +1245,7 @@ msgstr "мережі провайдерів" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1380,7 +1382,7 @@ msgstr "Завершено" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "Збій" @@ -1527,8 +1529,8 @@ msgid "User name" msgstr "Ім'я користувача" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1628,7 +1630,7 @@ msgid "Completed before" msgstr "Завершено раніше" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1674,23 +1676,23 @@ msgstr "Параметри бекенду" #: core/forms/model_forms.py:96 msgid "File Upload" -msgstr "Завантаження файлу" +msgstr "Вивантажити файл" #: core/forms/model_forms.py:108 msgid "Cannot upload a file and sync from an existing file" -msgstr "Не вдається завантажити файл і синхронізувати з існуючого файлу" +msgstr "Не вдається вивантажити файл і синхронізувати з існуючого файлу" #: core/forms/model_forms.py:110 msgid "Must upload a file or select a data file to sync" -msgstr "Потрібно завантажити файл або вибрати файл даних для синхронізації" +msgstr "Потрібно вивантажити файл або вибрати файл даних для синхронізації" #: core/forms/model_forms.py:153 templates/dcim/rack_elevation_list.html:6 msgid "Rack Elevations" msgstr "Висота стійки" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "Електрика" @@ -1777,7 +1779,7 @@ msgstr "зміна об'єкта" #: core/models/change_logging.py:107 msgid "object changes" -msgstr "зміни об'єкта" +msgstr "змін об'єкта" #: core/models/change_logging.py:123 #, python-brace-format @@ -1903,7 +1905,7 @@ msgstr "доріжка" #: core/models/data.py:283 msgid "File path relative to the data source's root" -msgstr "Шляху до файлу відносно кореня джерела даних" +msgstr "Шлях до файлу відносно кореня джерела даних" #: core/models/data.py:287 ipam/models/ip.py:503 msgid "size" @@ -1931,7 +1933,7 @@ msgstr "файли даних" #: core/models/data.py:401 msgid "auto sync record" -msgstr "запис автоматичної синхронізації" +msgstr "автоматична синхронізація запису" #: core/models/data.py:402 msgid "auto sync records" @@ -1947,7 +1949,7 @@ msgstr "шлях до файлу" #: core/models/files.py:44 msgid "File path relative to the designated root path" -msgstr "Шляху до файлу відносно призначеного кореневого шляху" +msgstr "Шлях до файлу відносно призначеного кореневого шляху" #: core/models/files.py:61 msgid "managed file" @@ -1988,7 +1990,7 @@ msgstr "помилка" #: core/models/jobs.py:100 msgid "job ID" -msgstr "iдентифікатор завдання" +msgstr "ідентифікатор завдання" #: core/models/jobs.py:111 msgid "job" @@ -2048,7 +2050,7 @@ msgstr "Є активним" #: core/tables/data.py:50 templates/core/datafile.html:31 msgid "Path" -msgstr "Шляху" +msgstr "Шлях" #: core/tables/data.py:54 templates/extras/inc/result_pending.html:7 msgid "Last updated" @@ -2064,7 +2066,7 @@ msgstr "Ідентифікатор" #: core/tables/jobs.py:35 msgid "Interval" -msgstr "інтервал" +msgstr "Інтервал" #: core/tables/plugins.py:14 templates/vpn/ipsecprofile.html:44 #: vpn/forms/bulk_edit.py:141 vpn/forms/bulk_import.py:172 @@ -2222,11 +2224,11 @@ msgstr "Завдання {id} було зупинено." msgid "Failed to stop job {id}" msgstr "Не вдалося зупинити завдання {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "Не вдалося завантажити каталог плагінів" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "Плагін {name} не знайдено" @@ -2244,7 +2246,7 @@ msgid "Staging" msgstr "Підготовка" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "Виведення з експлуатації" @@ -2304,7 +2306,7 @@ msgstr "Застарілий" msgid "Millimeters" msgstr "Міліметри" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "Дюйми" @@ -2316,8 +2318,8 @@ msgstr "Спереду ззаду" msgid "Rear to front" msgstr "Ззаду спереду" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2391,7 +2393,7 @@ msgstr "Знизу вгору" msgid "Top to bottom" msgstr "Зверху вниз" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "Пасивний" @@ -2419,8 +2421,8 @@ msgstr "Міжнародний/ITA" msgid "Proprietary" msgstr "Пропрієтарний" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "Інше" @@ -2433,22 +2435,22 @@ msgstr "ITA/Міжнародні" msgid "Physical" msgstr "Фізичний" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "Віртуальний" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "Бездротові мережі" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "Віртуальні інтерфейси" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2458,155 +2460,155 @@ msgstr "Віртуальні інтерфейси" msgid "Bridge" msgstr "Міст" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "Група агрегації каналів (LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "Ethernet (фіксований)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "Ethernet (модульний)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "Ethernet (панель)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "Стільниковий" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "Серійний" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "Коаксіальний" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "Стекований" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "Половинний" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "Повний" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "Авто" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "Доступ" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "З мітками" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "З мітками (Усі)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "Стандарт IEEE" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "Пасивний 24В (2-парний)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "Пасивний 24В (4-парний)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "Пасивний 48В (2-парний)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "Пасивний 48В (4-парний)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "Мідний" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "Волоконно-оптичний" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "Волоконний" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "Підключений" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "Кілометри" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "Метри" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "Сантиметри" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "Милі" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "Фути" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "Кілограми" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "Грами" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "Фунтів" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "Унцій" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "Надлишковий" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "Однофазний" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "Трифазний" @@ -2811,16 +2813,16 @@ msgstr "Платформа (ідентифікатор)" #: dcim/filtersets.py:1015 extras/filtersets.py:569 #: virtualization/filtersets.py:226 msgid "Platform (slug)" -msgstr "Платформа (скоречення)" +msgstr "Платформа (скорочення)" #: dcim/filtersets.py:1051 dcim/filtersets.py:1399 dcim/filtersets.py:1934 #: dcim/filtersets.py:2176 dcim/filtersets.py:2235 msgid "Site name (slug)" -msgstr "Назва тех. майданчика (скоречення)" +msgstr "Назва тех. майданчика (скорочення)" #: dcim/filtersets.py:1067 msgid "Parent bay (ID)" -msgstr "Батьківська бухта (ідентифікатор)" +msgstr "Батьківський відсік (ідентифікатор)" #: dcim/filtersets.py:1071 msgid "VM cluster (ID)" @@ -2829,7 +2831,7 @@ msgstr "Кластер віртуальних машини (ідентифіка #: dcim/filtersets.py:1077 extras/filtersets.py:591 #: virtualization/filtersets.py:136 msgid "Cluster group (slug)" -msgstr "Кластерна група (скоречення)" +msgstr "Кластерна група (скорочення)" #: dcim/filtersets.py:1082 virtualization/filtersets.py:130 msgid "Cluster group (ID)" @@ -2837,9 +2839,9 @@ msgstr "Група кластерів (ідентифікатор)" #: dcim/filtersets.py:1088 msgid "Device model (slug)" -msgstr "Модель пристрою (скоречення)" +msgstr "Модель пристрою (скорочення)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "Це повна глибина" @@ -2923,7 +2925,7 @@ msgstr "Роль пристрою (ідентифікатор)" #: dcim/filtersets.py:1453 msgid "Device role (slug)" -msgstr "Роль пристрою (скоречення)" +msgstr "Роль пристрою (скорочення)" #: dcim/filtersets.py:1458 msgid "Virtual Chassis (ID)" @@ -2955,7 +2957,7 @@ msgstr "Призначений VLAN" msgid "Assigned VID" msgstr "Призначений VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3049,7 +3051,7 @@ msgstr "Бездротова зв'язок" #: dcim/filtersets.py:1803 msgid "Parent module bay (ID)" -msgstr "Відсік батьківського модуля (iдентифікатор)" +msgstr "Відсік батьківського модуля (ідентифікатор)" #: dcim/filtersets.py:1808 msgid "Installed module (ID)" @@ -3077,7 +3079,7 @@ msgstr "Орендар (ідентифікатор)" #: dcim/filtersets.py:1945 extras/filtersets.py:618 tenancy/filtersets.py:251 msgid "Tenant (slug)" -msgstr "Орендар (скоречення)" +msgstr "Орендар (скорочення)" #: dcim/filtersets.py:1981 dcim/forms/filtersets.py:1077 msgid "Unterminated" @@ -3116,27 +3118,27 @@ msgstr "" "Підтримуються буквено-цифрові діапазони. (Повинен збігатися з кількістю " "створених імен.)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "Ім'я контакту" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "Контактний телефон" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "Контактна адреса електронної пошти" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "Часовий пояс" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3159,51 +3161,51 @@ msgstr "Часовий пояс" msgid "Manufacturer" msgstr "Виробник" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "Форм-фактор" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "Ширина" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "Висота (U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "Юніти у низхідному порядку" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "Зовнішня ширина" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "Зовнішня глибина" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "Зовнішній блок" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "Глибина монтажу" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3224,13 +3226,13 @@ msgstr "Глибина монтажу" msgid "Weight" msgstr "Вага" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "Максимальна вага" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3238,31 +3240,31 @@ msgstr "Максимальна вага" msgid "Weight unit" msgstr "Вага юніта" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "Тип стійки" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "Зовнішні розміри" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "Габарити" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "Нумерація" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3302,21 +3304,21 @@ msgstr "Нумерація" msgid "Role" msgstr "Роль" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "Серійний номер" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "Призначеня міток" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3326,7 +3328,7 @@ msgstr "Призначеня міток" msgid "Airflow" msgstr "Потік повітря" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3346,7 +3348,7 @@ msgstr "Потік повітря" msgid "Rack" msgstr "Стійка" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3355,49 +3357,49 @@ msgstr "Стійка" msgid "Hardware" msgstr "Апаратне забезпечення" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "Платформа за замовчуванням" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "Номер партії" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "Висота U" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "Виключити з утилізації" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "Тип пристрою" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "Тип модуля" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "Шасі" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "Роль віртуальної машини" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3410,19 +3412,19 @@ msgstr "Роль віртуальної машини" msgid "Config template" msgstr "Шаблон конфігурації" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "Тип пристрою" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "Роль пристрою" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3436,8 +3438,28 @@ msgstr "Роль пристрою" msgid "Platform" msgstr "Платформа" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "Кластер" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3494,22 +3516,27 @@ msgstr "Платформа" msgid "Device" msgstr "Пристрій" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "Конфігурація" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "Віртуалізація" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "Тип модуля" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3521,82 +3548,82 @@ msgstr "Тип модуля" msgid "Label" msgstr "Етикетка" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "Довжина" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "Довжина юніта" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "Домен" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "Панель живлення" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "Постачання" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "Фаза" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "Напруга" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "Сила струму" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "Максимальне використання" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "Максимальна потужність" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "Максимальна споживана потужність (Вт)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "Виділена потужність" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "Виділена споживана потужність (Вт)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "Порт живлення" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "Фідер живлення" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "Тільки управління" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3604,7 +3631,7 @@ msgstr "Тільки управління" msgid "PoE mode" msgstr "Режим PoE" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3612,12 +3639,12 @@ msgstr "Режим PoE" msgid "PoE type" msgstr "Тип PoE" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "Бездротова роль" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3627,16 +3654,16 @@ msgstr "Бездротова роль" msgid "Module" msgstr "Модуль" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "LAG" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "Контексти віртуальних пристроїв" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3645,7 +3672,7 @@ msgstr "Контексти віртуальних пристроїв" msgid "Speed" msgstr "Швидкість" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3656,36 +3683,44 @@ msgstr "Швидкість" msgid "Mode" msgstr "Режим" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "Група VLAN" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "VLAN без міток" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" -msgstr "VLAN з мітками" +msgstr "VLAN'и з мітками" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "Додати VLAN'и з мітками" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "Видалити мітки з VLAN'ів" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "Група бездротової локальної мережі" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "Бездротові локальні мережі" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3693,33 +3728,37 @@ msgstr "Бездротові локальні мережі" msgid "Addressing" msgstr "Адресація" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "Операція" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "Пов'язані інтерфейси" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "Комутація 802.1Q" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 -msgid "Interface mode must be specified to assign VLANs" -msgstr "Для призначення VLANs необхідно вказати режим інтерфейсу" +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "Додати/Видалити" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 +msgid "Interface mode must be specified to assign VLANs" +msgstr "Для призначення VLAN'ів необхідно вказати режим інтерфейсу" + +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "Інтерфейс доступу не може призначити VLAN'и з мітками." @@ -3860,26 +3899,6 @@ msgstr "Призначена платформа" msgid "Virtual chassis" msgstr "Віртуальне шасі" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "Кластер" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "Кластер віртуалізації" @@ -3993,7 +4012,7 @@ msgstr "Батьківський інтерфейс LAG" #: dcim/forms/bulk_import.py:854 msgid "Vdcs" -msgstr "Джерела живлення постійного струму " +msgstr "Джерела живлення постійного струму" #: dcim/forms/bulk_import.py:859 msgid "VDC names separated by commas, encased with double quotes. Example:" @@ -4108,7 +4127,7 @@ msgstr "Тип сторони А" #: dcim/forms/bulk_import.py:1180 dcim/forms/bulk_import.py:1198 msgid "Termination type" -msgstr "Тип припинення" +msgstr "Тип кінця" #: dcim/forms/bulk_import.py:1183 msgid "Side A name" @@ -4116,7 +4135,7 @@ msgstr "Назва сторони A" #: dcim/forms/bulk_import.py:1184 dcim/forms/bulk_import.py:1202 msgid "Termination name" -msgstr "Назва припинення" +msgstr "Назва кінця" #: dcim/forms/bulk_import.py:1189 msgid "Side B device" @@ -4178,7 +4197,7 @@ msgstr "Однофазний або трифазний (струм)" #: templates/dcim/device.html:190 templates/dcim/virtualdevicecontext.html:30 #: templates/virtualization/virtualmachine.html:52 msgid "Primary IPv4" -msgstr "Первинний IPv4" +msgstr "Первинна адреса IPv4" #: dcim/forms/bulk_import.py:1443 msgid "IPv4 address with mask, e.g. 1.2.3.4/24" @@ -4188,11 +4207,11 @@ msgstr "IPv4 адреса з маскою, наприклад 1.2.3.4/24" #: templates/dcim/device.html:206 templates/dcim/virtualdevicecontext.html:41 #: templates/virtualization/virtualmachine.html:68 msgid "Primary IPv6" -msgstr "Первинний IPv6" +msgstr "Первинна адреса IPv6" #: dcim/forms/bulk_import.py:1450 msgid "IPv6 address with prefix length, e.g. 2001:db8::1/64" -msgstr "IPv6 адреса з довжиною префікса, наприклад 2001:db8: :1/64" +msgstr "IPv6 адреса з довжиною префікса, наприклад 2001:db8::1/64" #: dcim/forms/common.py:24 dcim/models/device_components.py:527 #: templates/dcim/interface.html:57 @@ -4231,7 +4250,8 @@ msgstr "" #: dcim/forms/common.py:144 #, python-brace-format msgid "Cannot adopt {model} {name} as it already belongs to a module" -msgstr "Не можна усиновити {model} {name} оскільки він вже належить до модуля" +msgstr "" +"Не можна усиновити {model} {name}, оскільки він вже належить до модуля" #: dcim/forms/common.py:153 #, python-brace-format @@ -4548,7 +4568,7 @@ msgstr "Інтерфейс LAG" #: dcim/forms/model_forms.py:1355 msgid "Filter VLANs available for assignment by group." -msgstr "Фільтр VLAN, доступних для призначення за групами." +msgstr "Фільтр VLAN'ів, доступних для призначення за групами." #: dcim/forms/model_forms.py:1484 msgid "Child Device" @@ -4622,7 +4642,7 @@ msgid "" "match the selected number of rear port positions ({rearport_count})." msgstr "" "Кількість шаблонів передніх портів, які потрібно створити " -"({frontport_count}) повинен відповідати вибраній кількості позицій портів " +"({frontport_count}) повинна відповідати вибраній кількості позицій портів " "ззаду ({rearport_count})." #: dcim/forms/object_create.py:251 @@ -4631,8 +4651,8 @@ msgid "" "The string {module} will be replaced with the position of the " "assigned module, if any." msgstr "" -"Струна {module} буде замінено позицією призначеного модуля, " -"якщо такий є." +"Рядок {module} буде замінено позицією призначеного модуля, якщо" +" такий є." #: dcim/forms/object_create.py:320 #, python-brace-format @@ -4640,7 +4660,7 @@ msgid "" "The number of front ports to be created ({frontport_count}) must match the " "selected number of rear port positions ({rearport_count})." msgstr "" -"Кількість передніх портів, які потрібно створити ({frontport_count}) повинен" +"Кількість передніх портів, які потрібно створити ({frontport_count}) повинна" " відповідати вибраній кількості позицій портів ззаду ({rearport_count})." #: dcim/forms/object_create.py:409 dcim/tables/devices.py:1033 @@ -4663,7 +4683,7 @@ msgstr "" #: dcim/forms/object_create.py:435 msgid "A position must be specified for the first VC member." -msgstr "Посада повинна бути вказана для першого члена VC." +msgstr "Позиція повинна бути вказана для першого члена VC." #: dcim/models/cables.py:62 dcim/models/device_component_templates.py:55 #: dcim/models/device_components.py:62 extras/models/customfields.py:111 @@ -4692,7 +4712,7 @@ msgstr "Необхідно вказати номер юніта при уста #: dcim/models/cables.py:168 msgid "Must define A and B terminations when creating a new cable." -msgstr "Необхідно визначити кінцівки А і Б при створенні нового кабелю." +msgstr "Необхідно визначити кінці А і Б при створенні нового кабелю." #: dcim/models/cables.py:175 msgid "Cannot connect different termination types to same end of cable." @@ -4713,11 +4733,11 @@ msgstr "кінець" #: dcim/models/cables.py:313 msgid "cable termination" -msgstr "кабельна кінцівка" +msgstr "кабельний кінець" #: dcim/models/cables.py:314 msgid "cable terminations" -msgstr "кабельні кінцівки" +msgstr "кабельні кінці" #: dcim/models/cables.py:333 #, python-brace-format @@ -4725,7 +4745,7 @@ msgid "" "Duplicate termination found for {app_label}.{model} {termination_id}: cable " "{cable_pk}" msgstr "" -"Знайдено дублікат кінцівки {app_label}.{model} {termination_id}: кабель " +"Знайдено дублікат кінця {app_label}.{model} {termination_id}: кабель " "{cable_pk}" #: dcim/models/cables.py:343 @@ -4832,7 +4852,7 @@ msgstr "шаблони портів живлення" msgid "Allocated draw cannot exceed the maximum draw ({maximum_draw}W)." msgstr "" "Виділена потужність не може перевищувати максимальну потужність " -"({maximum_draw}W)." +"({maximum_draw}Вт)." #: dcim/models/device_component_templates.py:347 #: dcim/models/device_components.py:477 @@ -4856,14 +4876,14 @@ msgstr "шаблони розеток" #, python-brace-format msgid "Parent power port ({power_port}) must belong to the same device type" msgstr "" -"Батьківський порт живлення ({power_port}) повинні належати до одного типу " +"Батьківський порт живлення ({power_port}) повинен належати до одного типу " "пристрою" #: dcim/models/device_component_templates.py:371 #, python-brace-format msgid "Parent power port ({power_port}) must belong to the same module type" msgstr "" -"Батьківський порт живлення ({power_port}) повинні належати до одного типу " +"Батьківський порт живлення ({power_port}) повинен належати до одного типу " "модуля" #: dcim/models/device_component_templates.py:423 @@ -4949,7 +4969,7 @@ msgstr "шаблони портів ззаду" #: dcim/models/device_component_templates.py:662 #: dcim/models/device_components.py:1103 msgid "position" -msgstr "позиції" +msgstr "позиція" #: dcim/models/device_component_templates.py:665 #: dcim/models/device_components.py:1106 @@ -5534,7 +5554,7 @@ msgstr "" #: dcim/models/devices.py:337 msgid "Child device types must be 0U." -msgstr "Дитячі типи пристроїв повинні бути висоту 0 юніт." +msgstr "Підпорядковані типи пристроїв повинні бути висоту 0 юніт." #: dcim/models/devices.py:411 msgid "module type" @@ -5592,12 +5612,12 @@ msgstr "лицева частина стійки" #: dcim/models/devices.py:670 dcim/models/devices.py:1415 #: virtualization/models/virtualmachines.py:100 msgid "primary IPv4" -msgstr "первинний IPv4" +msgstr "первинна адреса IPv4" #: dcim/models/devices.py:678 dcim/models/devices.py:1423 #: virtualization/models/virtualmachines.py:108 msgid "primary IPv6" -msgstr "первинний IPv6" +msgstr "первинна адреса IPv6" #: dcim/models/devices.py:686 msgid "out-of-band IP" @@ -5652,7 +5672,7 @@ msgstr "Стійка {rack} не належить до тех. майданчи #: dcim/models/devices.py:840 #, python-brace-format msgid "Location {location} does not belong to site {site}." -msgstr "Розташування {location} не належить до тех. майданчика{site}." +msgstr "Розташування {location} не належить до тех. майданчика {site}." #: dcim/models/devices.py:846 #, python-brace-format @@ -5723,7 +5743,7 @@ msgstr "Зазначена IP-адреса ({ip}) не призначаєтьс #: dcim/models/devices.py:937 #, python-brace-format msgid "{ip} is not an IPv6 address." -msgstr "{ip} Це не IPv6 адреса ." +msgstr "{ip} Це не IPv6 адреса." #: dcim/models/devices.py:964 #, python-brace-format @@ -5819,7 +5839,7 @@ msgstr "контексти віртуальних пристроїв" #: dcim/models/devices.py:1482 #, python-brace-format msgid "{ip} is not an IPv{family} address." -msgstr "{ip} не є IPv{family} адресой." +msgstr "{ip} не є IPv{family} адресою." #: dcim/models/devices.py:1488 msgid "Primary IP address must belong to an interface on the assigned device." @@ -6073,7 +6093,8 @@ msgstr "бронювання стійки" #: dcim/models/racks.py:714 #, python-brace-format msgid "Invalid unit(s) for {height}U rack: {unit_list}" -msgstr "Недійсне монтажне місце для стійки висотою{height}юнітів: {unit_list}" +msgstr "" +"Недійсне монтажне місце для стійки висотою {height} юнітів: {unit_list}" #: dcim/models/racks.py:727 #, python-brace-format @@ -6086,7 +6107,7 @@ msgstr "Регіон верхнього рівня з такою назвою в #: dcim/models/sites.py:59 msgid "A top-level region with this slug already exists." -msgstr "Регіон верхнього рівня з цим слимаком вже існує." +msgstr "Регіон верхнього рівня з цим скореченням вже існує." #: dcim/models/sites.py:62 msgid "region" @@ -6102,7 +6123,7 @@ msgstr "Група тех. майданчиків верхнього рівня #: dcim/models/sites.py:112 msgid "A top-level site group with this slug already exists." -msgstr "Група тех. майданчиків верхнього рівня з цим слимаком вже існує." +msgstr "Група тех. майданчиків верхнього рівня з цим скореченням вже існує." #: dcim/models/sites.py:115 msgid "site group" @@ -6176,11 +6197,11 @@ msgstr "" #: dcim/tables/cables.py:55 msgid "Termination A" -msgstr "Припинення А" +msgstr "Кінець А" #: dcim/tables/cables.py:60 msgid "Termination B" -msgstr "Припинення Б" +msgstr "Кінець Б" #: dcim/tables/cables.py:66 wireless/tables/wirelesslink.py:23 msgid "Device A" @@ -6232,7 +6253,7 @@ msgstr "Пристрої" #: dcim/tables/devices.py:63 dcim/tables/devices.py:111 #: virtualization/tables/clusters.py:88 msgid "VMs" -msgstr "віртуальні машини" +msgstr "Віртуальні машини" #: dcim/tables/devices.py:100 dcim/tables/devices.py:216 #: extras/forms/model_forms.py:630 templates/dcim/device.html:112 @@ -6361,11 +6382,11 @@ msgstr "Позначене підключення" #: dcim/tables/devices.py:461 msgid "Maximum draw (W)" -msgstr "Максимальна потужність (W)" +msgstr "Максимальна потужність (Вт)" #: dcim/tables/devices.py:464 msgid "Allocated draw (W)" -msgstr "Виділена потужність (W)" +msgstr "Виділена потужність (Вт)" #: dcim/tables/devices.py:558 ipam/forms/model_forms.py:701 #: ipam/tables/fhrp.py:28 ipam/views.py:596 ipam/views.py:696 @@ -6397,7 +6418,7 @@ msgstr "Тільки управління" #: dcim/tables/devices.py:623 msgid "VDCs" -msgstr "Джерела живлення постійного струму " +msgstr "Джерела живлення постійного струму" #: dcim/tables/devices.py:873 templates/dcim/modulebay.html:53 msgid "Installed Module" @@ -6405,7 +6426,7 @@ msgstr "Встановлений модуль" #: dcim/tables/devices.py:876 msgid "Module Serial" -msgstr "Послідовний модуль " +msgstr "Послідовний модуль" #: dcim/tables/devices.py:880 msgid "Module Asset Tag" @@ -6449,7 +6470,7 @@ msgstr "Повна глибина" #: dcim/tables/devicetypes.py:98 msgid "U Height" -msgstr "Висота юніта" +msgstr "Висота юніта(U)" #: dcim/tables/devicetypes.py:113 dcim/tables/modules.py:26 #: dcim/tables/racks.py:89 @@ -6594,7 +6615,7 @@ msgstr "Контекст конфігурації" #: dcim/views.py:2098 virtualization/views.py:417 msgid "Render Config" -msgstr "Відтворювати конфігурацію" +msgstr "Відтворення конфігурації" #: dcim/views.py:2131 virtualization/views.py:450 #, python-brace-format @@ -6607,31 +6628,31 @@ msgstr "Під час візуалізації шаблону сталася п msgid "Virtual Machines" msgstr "Віртуальні машини" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "Встановлений пристрій {device} в бухті {device_bay}." -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "Видалений пристрій {device} з бухти {device_bay}." -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "Підпорядкований" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "Доданий член {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "Неможливо видалити головний пристрій {device} від віртуального шасі." -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "Вилучено {device} з віртуального шасі {chassis}" @@ -6667,7 +6688,7 @@ msgstr "Десяткове число" #: extras/choices.py:34 msgid "Boolean (true/false)" -msgstr "Булевий тип (істинна/хибна)" +msgstr "Булевий тип (правда/неправда)" #: extras/choices.py:35 msgid "Date" @@ -6969,7 +6990,7 @@ msgstr "Відображення довільного списку об'єкті #: extras/dashboard/widgets.py:222 msgid "The default number of objects to display" -msgstr "Типова кількість об'єктів для відображення" +msgstr "Кількість об'єктів за замовченням для відображення" #: extras/dashboard/widgets.py:234 msgid "Invalid format. URL parameters must be passed as a dictionary." @@ -7034,7 +7055,7 @@ msgstr "Тип кластера" #: extras/filtersets.py:580 virtualization/filtersets.py:95 #: virtualization/filtersets.py:147 msgid "Cluster type (slug)" -msgstr "Кластерний тип (скоречення)" +msgstr "Кластерний тип (скорочення)" #: extras/filtersets.py:601 tenancy/forms/forms.py:16 #: tenancy/forms/forms.py:39 @@ -7044,7 +7065,7 @@ msgstr "Група орендарів" #: extras/filtersets.py:607 tenancy/filtersets.py:188 #: tenancy/filtersets.py:208 msgid "Tenant group (slug)" -msgstr "Група орендарів (скоречення)" +msgstr "Група орендарів (скорочення)" #: extras/filtersets.py:623 extras/forms/model_forms.py:495 #: templates/extras/tag.html:11 @@ -7053,7 +7074,7 @@ msgstr "Мітка" #: extras/filtersets.py:629 msgid "Tag (slug)" -msgstr "Мітка (скоречення)" +msgstr "Мітка (скорочення)" #: extras/filtersets.py:689 extras/forms/filtersets.py:429 msgid "Has local config context data" @@ -7081,7 +7102,7 @@ msgstr "Видимий інтерфейс користувача" #: extras/forms/bulk_edit.py:66 extras/forms/bulk_import.py:66 #: extras/forms/filtersets.py:94 extras/models/customfields.py:216 msgid "UI editable" -msgstr "Редагований інтерфейс користувача " +msgstr "Редагований інтерфейс користувача" #: extras/forms/bulk_edit.py:71 extras/forms/filtersets.py:97 msgid "Is cloneable" @@ -7133,7 +7154,7 @@ msgstr "Спільний" #: extras/forms/bulk_edit.py:215 extras/forms/filtersets.py:265 #: extras/models/models.py:174 msgid "HTTP method" -msgstr "метод HTTP" +msgstr "Метод HTTP" #: extras/forms/bulk_edit.py:219 extras/forms/filtersets.py:259 #: templates/extras/webhook.html:30 @@ -7218,7 +7239,8 @@ msgid "" "separated by colon: \"choice1:First Choice,choice2:Second Choice\"" msgstr "" "Цитуючий рядок параметрів полів, розділених комами, з необов'язковими " -"мітками, розділеними двокрапкою: «Вибір1:Перший вибір, Вибір2:другий вибір»" +"мітками, розділеними двокрапкою: \"Вибір1:Перший вибір, Вибір2:другий " +"вибір\"" #: extras/forms/bulk_import.py:123 extras/models/models.py:323 msgid "button class" @@ -7456,7 +7478,7 @@ msgstr "Код шаблону" #: extras/forms/model_forms.py:247 templates/extras/exporttemplate.html:12 msgid "Export Template" -msgstr "Шаблон експорту" +msgstr "Експортувати шаблон" #: extras/forms/model_forms.py:249 msgid "Rendering" @@ -7574,19 +7596,19 @@ msgstr "Заплануйте виконання сценарію до встан msgid "Interval at which this script is re-run (in minutes)" msgstr "Інтервал повторного запуску сценарію (у хвилині)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "Зміни бази даних були автоматично скасовані." -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "Скрипт перерваний з помилкою: " -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "Виняток стався: " -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "Зміни бази даних були скасовані через помилку." @@ -7848,7 +7870,7 @@ msgstr "Поля виділення повинні вказувати набір #: extras/models/customfields.py:368 msgid "Choices may be set only on selection fields." -msgstr "Вибір можна встановити лише для полів виділення." +msgstr "Вибір можна встановити лише для виділених полів." #: extras/models/customfields.py:375 msgid "Object fields must define an object type." @@ -8183,7 +8205,7 @@ msgstr "" #: extras/models/models.py:410 msgid "Defaults to text/plain; charset=utf-8" -msgstr "За замовчуванням текст/простий; набір символів = utf-8" +msgstr "За замовчуванням text/plain; charset=utf-8" #: extras/models/models.py:413 msgid "file extension" @@ -8336,7 +8358,7 @@ msgstr "підписки" #: extras/models/scripts.py:42 msgid "is executable" -msgstr "виконуваний" +msgstr "є виконуваним" #: extras/models/scripts.py:64 msgid "script" @@ -8380,7 +8402,7 @@ msgstr "гілка" #: extras/models/staging.py:45 msgid "branches" -msgstr "відділення" +msgstr "гілки" #: extras/models/staging.py:97 msgid "staged change" @@ -8465,7 +8487,7 @@ msgstr "Максимальне значення" #: extras/tables/tables.py:104 msgid "Validation Regex" -msgstr "Перевірка регулярного вираза " +msgstr "Перевірка регулярного вираза" #: extras/tables/tables.py:137 msgid "Count" @@ -8617,7 +8639,8 @@ msgstr "Невірний формат IP-адреси: {data}" #: ipam/api/field_serializers.py:37 msgid "Enter a valid IPv4 or IPv6 prefix and mask in CIDR notation." -msgstr "Введіть дійсний префікс IPv4 або IPv6 та маску в позначенні CIDR." +msgstr "" +"Введіть дійсний мережевий префікс IPv4 або IPv6 та маску в позначенні CIDR." #: ipam/api/field_serializers.py:44 #, python-brace-format @@ -8639,11 +8662,11 @@ msgstr "DHCP" #: ipam/choices.py:73 msgid "SLAAC" -msgstr "СЛААК" +msgstr "SLAAC" #: ipam/choices.py:89 msgid "Loopback" -msgstr "Петлебек" +msgstr "Loopback" #: ipam/choices.py:91 msgid "Anycast" @@ -8729,15 +8752,15 @@ msgstr "RIR (ідентифікатор)" #: ipam/filtersets.py:165 ipam/filtersets.py:204 ipam/filtersets.py:227 msgid "RIR (slug)" -msgstr "RIR (скоречення)" +msgstr "RIR (скорочення)" #: ipam/filtersets.py:285 msgid "Within prefix" -msgstr "Всередині префікса" +msgstr "У межах префікса" #: ipam/filtersets.py:289 msgid "Within and including prefix" -msgstr "Всередині та включаючи префікс" +msgstr "У межах та включаючи префікс" #: ipam/filtersets.py:293 msgid "Prefixes which contain this prefix or IP" @@ -8811,7 +8834,7 @@ msgstr "Сервіс (ідентифікатор)" #: ipam/filtersets.py:673 msgid "NAT inside IP address (ID)" -msgstr "NAT всередині IP-адреси (ідентифікатор)" +msgstr "NAT внутрішня IP-адреса (ідентифікатор)" #: ipam/filtersets.py:1041 ipam/forms/bulk_import.py:322 msgid "Assigned interface" @@ -8831,11 +8854,11 @@ msgstr "IP-адреса" #: ipam/filtersets.py:1167 msgid "Primary IPv4 (ID)" -msgstr "Первинний IPv4 (ідентифікатор)" +msgstr "Первинна адреса IPv4 (ідентифікатор)" #: ipam/filtersets.py:1172 msgid "Primary IPv6 (ID)" -msgstr "Первинний IPv6 (ідентифікатор)" +msgstr "Первинна адреса IPv6 (ідентифікатор)" #: ipam/formfields.py:14 msgid "Enter a valid IPv4 or IPv6 address (without a mask)." @@ -8868,7 +8891,7 @@ msgstr "Адресний шаблон" #: ipam/forms/bulk_edit.py:50 msgid "Enforce unique space" -msgstr "Забезпечте унікальний простір" +msgstr "Забезпечте унікальність простору" #: ipam/forms/bulk_edit.py:88 msgid "Is private" @@ -8886,7 +8909,7 @@ msgstr "Є приватним" #: templates/ipam/aggregate.html:18 templates/ipam/asn.html:27 #: templates/ipam/asnrange.html:19 templates/ipam/rir.html:19 msgid "RIR" -msgstr "ЗРИГНУТИ" +msgstr "RIR" #: ipam/forms/bulk_edit.py:171 msgid "Date added" @@ -8900,7 +8923,7 @@ msgstr "Група VLAN" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -8918,13 +8941,13 @@ msgstr "Довжина префікса" #: ipam/forms/bulk_edit.py:268 ipam/forms/filtersets.py:241 #: templates/ipam/prefix.html:85 msgid "Is a pool" -msgstr "Чи є басейн" +msgstr "Чи є пулом" #: ipam/forms/bulk_edit.py:273 ipam/forms/bulk_edit.py:318 #: ipam/forms/filtersets.py:248 ipam/forms/filtersets.py:293 #: ipam/models/ip.py:272 ipam/models/ip.py:539 msgid "Treat as fully utilized" -msgstr "Ставтеся до повного використання" +msgstr "Вважати повністю використаним" #: ipam/forms/bulk_edit.py:287 ipam/forms/filtersets.py:171 msgid "VLAN Assignment" @@ -8997,11 +9020,11 @@ msgstr "Порти" #: ipam/forms/bulk_import.py:48 msgid "Import route targets" -msgstr "Імпортувати цілі маршруту" +msgstr "Імпортувати маршрути до цілей" #: ipam/forms/bulk_import.py:54 msgid "Export route targets" -msgstr "Експортувати цілі маршруту" +msgstr "Експортувати маршрути до цілей" #: ipam/forms/bulk_import.py:92 ipam/forms/bulk_import.py:112 #: ipam/forms/bulk_import.py:132 @@ -9010,7 +9033,7 @@ msgstr "Призначений RIR" #: ipam/forms/bulk_import.py:182 msgid "VLAN's group (if any)" -msgstr "Група VLAN (якщо така є)" +msgstr "Група VLAN'ів (якщо така є)" #: ipam/forms/bulk_import.py:308 msgid "Parent device of assigned interface (if any)" @@ -9044,12 +9067,12 @@ msgstr "Зробіть це основним IP для призначеного #: ipam/forms/bulk_import.py:365 msgid "No device or virtual machine specified; cannot set as primary IP" msgstr "" -"Пристрій або віртуальна машина не вказано; неможливо встановити як основний " -"IP" +"Пристрій або віртуальна машина не вказано; неможливо встановити як первинний" +" IP" #: ipam/forms/bulk_import.py:369 msgid "No interface specified; cannot set as primary IP" -msgstr "Інтерфейс не вказано; неможливо встановити як основний IP" +msgstr "Інтерфейс не вказано; неможливо встановити як первинний IP" #: ipam/forms/bulk_import.py:398 msgid "Auth type" @@ -9069,11 +9092,11 @@ msgstr "протокол IP" #: ipam/forms/bulk_import.py:485 msgid "Required if not assigned to a VM" -msgstr "Необхідний, якщо він не призначений для віртуальної машини" +msgstr "Необхідний, якщо він не був призначений для віртуальної машини" #: ipam/forms/bulk_import.py:492 msgid "Required if not assigned to a device" -msgstr "Обов'язково, якщо пристрій не призначений" +msgstr "Обов'язково, якщо він не був призначений для пристрою" #: ipam/forms/bulk_import.py:517 #, python-brace-format @@ -9083,7 +9106,7 @@ msgstr "{ip} не призначається цьому пристрою/вір #: ipam/forms/filtersets.py:47 ipam/forms/model_forms.py:63 #: netbox/navigation/menu.py:189 vpn/forms/model_forms.py:410 msgid "Route Targets" -msgstr "Маршрутні цілі" +msgstr "Маршрути до цілей" #: ipam/forms/filtersets.py:53 ipam/forms/model_forms.py:50 #: vpn/forms/filtersets.py:224 vpn/forms/model_forms.py:397 @@ -9093,15 +9116,15 @@ msgstr "Імпортувати цілі" #: ipam/forms/filtersets.py:58 ipam/forms/model_forms.py:55 #: vpn/forms/filtersets.py:229 vpn/forms/model_forms.py:402 msgid "Export targets" -msgstr "Експортні цілі" +msgstr "Експортувати цілі" #: ipam/forms/filtersets.py:73 msgid "Imported by VRF" -msgstr "Імпортований VRF" +msgstr "Імпортований до VRF" #: ipam/forms/filtersets.py:78 msgid "Exported by VRF" -msgstr "Експортується VRF" +msgstr "Експортувати з VRF" #: ipam/forms/filtersets.py:87 ipam/tables/ip.py:89 templates/ipam/rir.html:30 msgid "Private" @@ -9110,7 +9133,7 @@ msgstr "Приватний" #: ipam/forms/filtersets.py:105 ipam/forms/filtersets.py:191 #: ipam/forms/filtersets.py:272 ipam/forms/filtersets.py:326 msgid "Address family" -msgstr "Адреса сім'ї" +msgstr "Сімейство адрес" #: ipam/forms/filtersets.py:119 templates/ipam/asnrange.html:25 msgid "Range" @@ -9126,7 +9149,7 @@ msgstr "Кінець" #: ipam/forms/filtersets.py:186 msgid "Search within" -msgstr "Пошук всередині" +msgstr "Пошук в межах" #: ipam/forms/filtersets.py:207 ipam/forms/filtersets.py:342 msgid "Present in VRF" @@ -9142,34 +9165,34 @@ msgstr "Батьківський префікс" #: ipam/forms/filtersets.py:347 msgid "Assigned Device" -msgstr "Призначений пристрій" +msgstr "Призначено на пристрій" #: ipam/forms/filtersets.py:352 msgid "Assigned VM" -msgstr "Призначена віртуальна машина" +msgstr "Призначено на віртуальну машину" #: ipam/forms/filtersets.py:366 msgid "Assigned to an interface" -msgstr "Призначено до інтерфейсу" +msgstr "Призначено на інтерфейс" #: ipam/forms/filtersets.py:373 templates/ipam/ipaddress.html:51 msgid "DNS Name" msgstr "Ім'я DNS" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" -msgstr "VLANs" +msgstr "VLAN'и" #: ipam/forms/filtersets.py:457 msgid "Contains VLAN ID" msgstr "Містить ідентифікатор VLAN" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" -msgstr "ІДЕНТИФІКАТОР VLAN" +msgstr "Ідентифікатор VLAN" #: ipam/forms/filtersets.py:556 ipam/forms/model_forms.py:320 #: ipam/forms/model_forms.py:713 ipam/forms/model_forms.py:739 @@ -9190,7 +9213,7 @@ msgstr "Віртуальна машина" #: ipam/forms/model_forms.py:80 templates/ipam/routetarget.html:10 msgid "Route Target" -msgstr "Мета маршруту" +msgstr "Маршрут до цілі" #: ipam/forms/model_forms.py:114 ipam/tables/ip.py:117 #: templates/ipam/aggregate.html:11 templates/ipam/prefix.html:38 @@ -9220,7 +9243,7 @@ msgstr "Зробіть це основним IP для пристрою/вірт #: ipam/forms/model_forms.py:325 msgid "NAT IP (Inside)" -msgstr "NAT IP (всередині)" +msgstr "NAT IP (внутрішній)" #: ipam/forms/model_forms.py:384 msgid "An IP address can only be assigned to a single object." @@ -9231,15 +9254,15 @@ msgid "" "Cannot reassign IP address while it is designated as the primary IP for the " "parent object" msgstr "" -"Не вдається перепризначити IP-адресу, поки вона призначена як основний IP " +"Не вдається перепризначити IP-адресу, поки вона призначена як первинний IP " "для батьківського об'єкта" #: ipam/forms/model_forms.py:400 msgid "" "Only IP addresses assigned to an interface can be designated as primary IPs." msgstr "" -"Тільки IP-адреси, призначені інтерфейсу, можуть бути визначені основними IP-" -"адресами." +"Тільки IP-адреси, призначені інтерфейсу, можуть бути визначені первинними " +"IP-адресами." #: ipam/forms/model_forms.py:475 msgid "Virtual IP Address" @@ -9255,7 +9278,7 @@ msgstr "Ідентифікатори VLAN" #: ipam/forms/model_forms.py:587 msgid "Child VLANs" -msgstr "Дитячі VLAN" +msgstr "Підпорядковані VLAN'и" #: ipam/forms/model_forms.py:664 ipam/forms/model_forms.py:696 msgid "" @@ -9294,8 +9317,8 @@ msgstr "Користувацький" msgid "" "Must specify name, protocol, and port(s) if not using a service template." msgstr "" -"Необхідно вказати ім'я, протокол та порт (и), якщо не використовується " -"шаблон служби." +"Необхідно вказати ім'я, протокол та порт(и), якщо не використовується шаблон" +" служби." #: ipam/models/asns.py:34 msgid "start" @@ -9312,11 +9335,11 @@ msgstr "Діапазони ASN" #: ipam/models/asns.py:72 #, python-brace-format msgid "Starting ASN ({start}) must be lower than ending ASN ({end})." -msgstr "Запуск ASN ({start}) повинен бути нижчим за кінцевий ASN ({end})." +msgstr "Початковий ASN ({start}) повинен бути нижчим за кінцевий ASN ({end})." #: ipam/models/asns.py:104 msgid "Regional Internet Registry responsible for this AS number space" -msgstr "Регіональний інтернет-реєстр, відповідальний за цей номер AS" +msgstr "Регіональний інтернет-реєстр(RIR), відповідальний за цей номер AS" #: ipam/models/asns.py:109 msgid "16- or 32-bit autonomous system number" @@ -9324,7 +9347,7 @@ msgstr "16- або 32-розрядний номер автономної сис #: ipam/models/fhrp.py:22 msgid "group ID" -msgstr "Ідентифікатор групи" +msgstr "ідентифікатор групи" #: ipam/models/fhrp.py:30 ipam/models/services.py:22 msgid "protocol" @@ -9364,7 +9387,7 @@ msgstr "Простір IP, керований цим RIR, вважається #: ipam/models/ip.py:72 netbox/navigation/menu.py:182 msgid "RIRs" -msgstr "RIR" +msgstr "RIRи" #: ipam/models/ip.py:84 msgid "IPv4 or IPv6 network" @@ -9372,7 +9395,7 @@ msgstr "Мережа IPv4 або IPv6" #: ipam/models/ip.py:91 msgid "Regional Internet Registry responsible for this IP space" -msgstr "Регіональний Інтернет-реєстр, відповідальний за цей IP-простір" +msgstr "Регіональний Інтернет-реєстр(RIR), відповідальний за цей IP-простір" #: ipam/models/ip.py:101 msgid "date added" @@ -9384,11 +9407,11 @@ msgstr "сукупний" #: ipam/models/ip.py:116 msgid "aggregates" -msgstr "агреговані мережі" +msgstr "сукупні мережі" #: ipam/models/ip.py:132 msgid "Cannot create aggregate with /0 mask." -msgstr "Не вдається створити агрегат з маскою /0." +msgstr "Не вдається створити сукупну мережу з маскою /0." #: ipam/models/ip.py:144 #, python-brace-format @@ -9396,8 +9419,8 @@ msgid "" "Aggregates cannot overlap. {prefix} is already covered by an existing " "aggregate ({aggregate})." msgstr "" -"Агрегати не можуть перекриватися. {prefix} вже покривається існуючим " -"агрегатом ({aggregate})." +"Сукупні мережі не можуть перекриватися. {prefix} вже покривається існуючим " +"сукупною мережею ({aggregate})." #: ipam/models/ip.py:158 #, python-brace-format @@ -9405,8 +9428,8 @@ msgid "" "Prefixes cannot overlap aggregates. {prefix} covers an existing aggregate " "({aggregate})." msgstr "" -"Мережеві префікси не можуть перекривати агрегати. {prefix} охоплює існуючий " -"агрегат ({aggregate})." +"Мережеві префікси не можуть перекривати сукупні мережі. {prefix} охоплює " +"існуючий сукупну мережу ({aggregate})." #: ipam/models/ip.py:200 ipam/models/ip.py:737 vpn/models/tunnels.py:114 msgid "role" @@ -9434,7 +9457,7 @@ msgstr "Основна функція цього префікса" #: ipam/models/ip.py:265 msgid "is a pool" -msgstr "є басейном" +msgstr "є у пулі" #: ipam/models/ip.py:267 msgid "All IP addresses within this prefix are considered usable" @@ -9455,7 +9478,7 @@ msgstr "Неможливо створити префікс з маскою /0." #: ipam/models/ip.py:324 ipam/models/ip.py:874 #, python-brace-format msgid "VRF {vrf}" -msgstr "ВРФ {vrf}" +msgstr "VRF {vrf}" #: ipam/models/ip.py:324 ipam/models/ip.py:874 msgid "global table" @@ -9513,7 +9536,7 @@ msgstr "" #, python-brace-format msgid "Defined addresses overlap with range {overlapping_range} in VRF {vrf}" msgstr "" -"Визначені адреси перекриваються з діапазоном {overlapping_range} в ВРФ {vrf}" +"Визначені адреси перекриваються з діапазоном {overlapping_range} в VRF {vrf}" #: ipam/models/ip.py:599 #, python-brace-format @@ -9527,19 +9550,19 @@ msgstr "адреса" #: ipam/models/ip.py:734 msgid "The operational status of this IP" -msgstr "Операційний стан цього ІП" +msgstr "Операційний стан цього IP" #: ipam/models/ip.py:741 msgid "The functional role of this IP" -msgstr "Функціональна роль цього ІП" +msgstr "Функціональна роль цього IP" #: ipam/models/ip.py:765 templates/ipam/ipaddress.html:72 msgid "NAT (inside)" -msgstr "NAT (всередині)" +msgstr "NAT (внутрішній)" #: ipam/models/ip.py:766 msgid "The IP for which this address is the \"outside\" IP" -msgstr "IP, для якого ця адреса є \"зовнішнім\" IP" +msgstr "IP, для якого ця адреса є \"зовнішньою\"" #: ipam/models/ip.py:773 msgid "Hostname or FQDN (not case-sensitive)" @@ -9563,7 +9586,7 @@ msgstr "" #, python-brace-format msgid "" "{ip} is a broadcast address, which may not be assigned to an interface." -msgstr "{ip} це адреса трансляції, яка може не бути присвоєна інтерфейсу." +msgstr "{ip} це широкомовна адреса, яка може не бути присвоєна інтерфейсу." #: ipam/models/ip.py:876 #, python-brace-format @@ -9622,40 +9645,54 @@ msgstr "Не вдається встановити scope_type без scope_id." msgid "Cannot set scope_id without scope_type." msgstr "Не вдається встановити scope_id без scope_type." -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" +"Початковий ідентифікатор VLAN в діапазоні ({value}) не може бути менше " +"{minimum}" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" +"Кінцевий ідентифікатор VLAN в діапазоні ({value}) не може перевищувати " +"{maximum}" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" +"Кінцевий ідентифікатор VLAN в діапазоні повинен бути більшим або дорівнювати" +" початковому ідентифікатору VLAN ({range})" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "Діапазони не можуть перекриватися." -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "" -"Максимальний підпорядкований VID повинен бути більшим або дорівнює " -"мінімальному підпорядкований VID ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "Конкретний тех. майданчик, якому присвоєно цей VLAN (якщо такий є)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "Група VLAN (необов'язково)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "Числовий ідентифікатор VLAN (1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "Операційний стан цього VLAN" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "Основна функція цього VLAN" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " @@ -9664,18 +9701,19 @@ msgstr "" "VLAN присвоюється групі {group} (сфера застосування: {scope}); також не може" " призначатися до тех. майданчику {site}." -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" -msgstr "VID повинен знаходитися в діапазоні {ranges} для VLAN в групі {group}" +msgstr "" +"VID повинен знаходитися в діапазоні {ranges} для VLAN'ів у групі {group}" #: ipam/models/vrfs.py:30 msgid "route distinguisher" -msgstr "розрізнювач маршруту" +msgstr "розрізнювач маршруту (RD)" #: ipam/models/vrfs.py:31 msgid "Unique route distinguisher (as defined in RFC 4364)" -msgstr "Унікальний розрізнювач маршруту (як визначено в RFC 4364)" +msgstr "Унікальний розрізнювач маршруту (RD) (як визначено в RFC 4364)" #: ipam/models/vrfs.py:42 msgid "enforce unique space" @@ -9688,7 +9726,7 @@ msgstr "Запобігання дублікуванню префіксів/IP-а #: ipam/models/vrfs.py:63 netbox/navigation/menu.py:186 #: netbox/navigation/menu.py:188 msgid "VRFs" -msgstr "VRF" +msgstr "VRFи" #: ipam/models/vrfs.py:82 msgid "Route target value (formatted in accordance with RFC 4360)" @@ -9696,15 +9734,15 @@ msgstr "Цільове значення маршруту (відформатов #: ipam/models/vrfs.py:94 msgid "route target" -msgstr "цільовий маршрут" +msgstr "маршрут до цілі" #: ipam/models/vrfs.py:95 msgid "route targets" -msgstr "маршрутні цілі" +msgstr "маршрут до цілей" #: ipam/tables/asn.py:52 msgid "ASDOT" -msgstr "АСДОТ" +msgstr "ASDOT" #: ipam/tables/asn.py:57 msgid "Site Count" @@ -9717,7 +9755,7 @@ msgstr "Кількість провайдерів" #: ipam/tables/ip.py:95 netbox/navigation/menu.py:179 #: netbox/navigation/menu.py:181 msgid "Aggregates" -msgstr "Агрегати" +msgstr "Сукупні мережі" #: ipam/tables/ip.py:125 msgid "Added" @@ -9750,11 +9788,11 @@ msgstr "Глибина" #: ipam/tables/ip.py:262 msgid "Pool" -msgstr "Басейн" +msgstr "Пул" #: ipam/tables/ip.py:266 ipam/tables/ip.py:320 msgid "Marked Utilized" -msgstr "Позначений Використовуваний" +msgstr "Позначено як використане" #: ipam/tables/ip.py:304 msgid "Start address" @@ -9762,15 +9800,15 @@ msgstr "Початкова адреса" #: ipam/tables/ip.py:383 msgid "NAT (Inside)" -msgstr "NAT (всередині)" +msgstr "NAT (внутрішній)" #: ipam/tables/ip.py:388 msgid "NAT (Outside)" -msgstr "NAT (зовні)" +msgstr "NAT (зовнішній)" #: ipam/tables/ip.py:393 msgid "Assigned" -msgstr "Призначено" +msgstr "Призначений" #: ipam/tables/ip.py:429 templates/vpn/l2vpntermination.html:16 #: vpn/forms/filtersets.py:240 @@ -9788,11 +9826,11 @@ msgstr "Діапазони VID" #: ipam/tables/vlans.py:111 ipam/tables/vlans.py:214 #: templates/dcim/inc/interface_vlans_table.html:4 msgid "VID" -msgstr "ВИД" +msgstr "VID" #: ipam/tables/vrfs.py:30 msgid "RD" -msgstr "Р-Н" +msgstr "RD" #: ipam/tables/vrfs.py:33 msgid "Unique" @@ -9804,7 +9842,7 @@ msgstr "Імпортувати цілі" #: ipam/tables/vrfs.py:42 vpn/tables/l2vpn.py:32 msgid "Export Targets" -msgstr "Експортні цілі" +msgstr "Експортувати цілі" #: ipam/validators.py:9 #, python-brace-format @@ -9814,12 +9852,12 @@ msgstr "{prefix} не є дійсним префіксом. Ви мали на #: ipam/validators.py:16 #, python-format msgid "The prefix length must be less than or equal to %(limit_value)s." -msgstr "Довжина префікса повинна бути менше або дорівнює %(limit_value)s." +msgstr "Довжина префікса повинна бути менше або дорівнює %(limit_value)sи." #: ipam/validators.py:24 #, python-format msgid "The prefix length must be greater than or equal to %(limit_value)s." -msgstr "Довжина префікса повинна бути більше або дорівнює %(limit_value)s." +msgstr "Довжина префікса повинна бути більше або дорівнює %(limit_value)sи." #: ipam/validators.py:33 msgid "" @@ -9835,7 +9873,7 @@ msgstr "Підпорядковані мережеві префікси" #: ipam/views.py:569 msgid "Child Ranges" -msgstr "Дитячі діапазони" +msgstr "Підпорядковані діапазони" #: ipam/views.py:898 msgid "Related IPs" @@ -9843,7 +9881,7 @@ msgstr "Пов'язані IP-адреси" #: ipam/views.py:1127 msgid "Device Interfaces" -msgstr "Інтерфейси пристроїв" +msgstr "Інтерфейси пристрою" #: ipam/views.py:1145 msgid "VM Interfaces" @@ -9877,7 +9915,7 @@ msgstr "Невірне значення. Вкажіть тип вмісту як #: netbox/api/fields.py:167 msgid "Ranges must be specified in the form (lower, upper)." -msgstr "Діапазони повинні бути вказані в формі (нижній, верхній)." +msgstr "Діапазони повинні бути вказані у форматі (нижня межа, верхня межа)." #: netbox/api/fields.py:169 msgid "Range boundaries must be defined as integers." @@ -9899,11 +9937,11 @@ msgstr "Темно-червоний" #: netbox/choices.py:52 msgid "Rose" -msgstr "Роза" +msgstr "Трояндовий" #: netbox/choices.py:53 msgid "Fuchsia" -msgstr "Фуксія" +msgstr "Малиновий" #: netbox/choices.py:55 msgid "Dark Purple" @@ -9915,7 +9953,7 @@ msgstr "Світло-блакитний" #: netbox/choices.py:61 msgid "Aqua" -msgstr "Аква" +msgstr "Бирюзовый" #: netbox/choices.py:62 msgid "Dark Green" @@ -9927,11 +9965,11 @@ msgstr "Світло-зелений" #: netbox/choices.py:65 msgid "Lime" -msgstr "Лайм" +msgstr "Кислотно-зелений" #: netbox/choices.py:67 msgid "Amber" -msgstr "Бурштин" +msgstr "Бурштиновий" #: netbox/choices.py:69 msgid "Dark Orange" @@ -9943,7 +9981,7 @@ msgstr "Коричневий" #: netbox/choices.py:71 msgid "Light Grey" -msgstr "Світло-сірий" +msgstr "Сріблясто-сірий" #: netbox/choices.py:72 msgid "Grey" @@ -9951,7 +9989,7 @@ msgstr "Сірий" #: netbox/choices.py:73 msgid "Dark Grey" -msgstr "Темно-сірий" +msgstr "Антрацитовий" #: netbox/choices.py:128 msgid "Direct" @@ -9959,7 +9997,7 @@ msgstr "прямий" #: netbox/choices.py:129 msgid "Upload" -msgstr "Завантажити" +msgstr "Вивантажити" #: netbox/choices.py:141 netbox/choices.py:155 msgid "Auto-detect" @@ -9975,7 +10013,7 @@ msgstr "Крапка з комою" #: netbox/choices.py:158 msgid "Tab" -msgstr "Вкладка" +msgstr "Табуляція" #: netbox/config/__init__.py:67 #, python-brace-format @@ -10032,19 +10070,19 @@ msgstr "Віддавайте перевагу IPv4 адресам над IPv6" #: netbox/config/parameters.py:84 msgid "Rack unit height" -msgstr "Висота юніта стійки" +msgstr "Висота стійки у юнітах" #: netbox/config/parameters.py:86 msgid "Default unit height for rendered rack elevations" -msgstr "Висота юніта за замовчуванням для візуалізованих висот стійки" +msgstr "Висота одиниці за замовчуванням для візуалізованих стійки" #: netbox/config/parameters.py:91 msgid "Rack unit width" -msgstr "Ширина юніта стійки" +msgstr "Ширина стійки у юнітах" #: netbox/config/parameters.py:93 msgid "Default unit width for rendered rack elevations" -msgstr "Типова одиниця ширини для візуалізованих висот стійки" +msgstr "Ширина одиниці за замовчуванням для візуалізованих стійки" #: netbox/config/parameters.py:100 msgid "Powerfeed voltage" @@ -10060,7 +10098,7 @@ msgstr "Сила струму подачі живлення" #: netbox/config/parameters.py:109 msgid "Default amperage for powerfeeds" -msgstr "Сила струму за замовчуванням для подачі живлення" +msgstr "Сила струму за замовчуванням при подачі живлення" #: netbox/config/parameters.py:114 msgid "Powerfeed max utilization" @@ -10068,7 +10106,7 @@ msgstr "Максимальне використання при подачі жи #: netbox/config/parameters.py:116 msgid "Default max utilization for powerfeeds" -msgstr "Максимальне використання за замовчуванням для подач живлення" +msgstr "Максимальне використання за замовчуванням при подачі живлення" #: netbox/config/parameters.py:123 templates/core/inc/config_data.html:53 msgid "Allowed URL schemes" @@ -10112,7 +10150,7 @@ msgstr "Налаштування за замовчуванням для нови #: netbox/config/parameters.py:181 templates/core/inc/config_data.html:129 msgid "Maintenance mode" -msgstr "Режим обслуговування" +msgstr "Режим технічного обслуговування" #: netbox/config/parameters.py:183 msgid "Enable maintenance mode" @@ -10168,11 +10206,11 @@ msgstr "Починається з" #: netbox/forms/__init__.py:15 msgid "Ends with" -msgstr "Закінчується з" +msgstr "Закінчується на" #: netbox/forms/__init__.py:16 msgid "Regex" -msgstr "Регекс" +msgstr "Регулярний вираз" #: netbox/forms/__init__.py:34 msgid "Object type(s)" @@ -10187,8 +10225,8 @@ msgid "" "Tag slugs separated by commas, encased with double quotes (e.g. " "\"tag1,tag2,tag3\")" msgstr "" -"Слимаки міток, розділені комами, укладені подвійними лапками (наприклад, " -"\"tag1, tag2, tag3\")" +"Мітки скорочень, розділені комами, укладені подвійними лапками (наприклад, " +"\"мітка1, мітка2, мітка3\")" #: netbox/forms/base.py:120 msgid "Add tags" @@ -10233,11 +10271,11 @@ msgstr "шлях даних" #: netbox/models/features.py:476 msgid "Path to remote file (relative to data source root)" -msgstr "Шляху до віддаленого файлу (відносно кореня джерела даних)" +msgstr "Шлях до віддаленого файлу (відносно кореня джерела даних)" #: netbox/models/features.py:479 msgid "auto sync enabled" -msgstr "увімкнено автоматичну синхронізацію" +msgstr "увімкнути автоматичну синхронізацію" #: netbox/models/features.py:481 msgid "Enable automatic synchronization of data when the data file is updated" @@ -10250,7 +10288,7 @@ msgstr "дата синхронізована" #: netbox/models/features.py:578 #, python-brace-format msgid "{class_name} must implement a sync_data() method." -msgstr "{class_name} повинен реалізувати метод sync_data ()." +msgstr "{class_name} повинен реалізувати метод sync_data()." #: netbox/navigation/menu.py:11 msgid "Organization" @@ -10323,7 +10361,7 @@ msgstr "Бездротові зв'язки" #: netbox/navigation/menu.py:121 msgid "Interface Connections" -msgstr "Інтерфейсні з'єднання" +msgstr "Інтерфейсні підключення" #: netbox/navigation/menu.py:126 msgid "Console Connections" @@ -10335,7 +10373,7 @@ msgstr "Підключення живлення" #: netbox/navigation/menu.py:147 msgid "Wireless LAN Groups" -msgstr "Групи бездротової локальної мережі" +msgstr "Групи WLAN" #: netbox/navigation/menu.py:168 msgid "Prefix & VLAN Roles" @@ -10374,7 +10412,7 @@ msgstr "Тунельні групи" #: netbox/navigation/menu.py:219 msgid "Tunnel Terminations" -msgstr "Закінчення тунелів" +msgstr "Кінці тунелів" #: netbox/navigation/menu.py:223 netbox/navigation/menu.py:225 #: vpn/models/l2vpn.py:64 @@ -10384,11 +10422,11 @@ msgstr "L2VPN" #: netbox/navigation/menu.py:226 templates/vpn/l2vpn.html:56 #: templates/vpn/tunnel.html:72 vpn/tables/tunnels.py:58 msgid "Terminations" -msgstr "Припинення" +msgstr "Кінці" #: netbox/navigation/menu.py:232 msgid "IKE Proposals" -msgstr "Пропозиції IKE" +msgstr "Налаштування IKE" #: netbox/navigation/menu.py:233 templates/vpn/ikeproposal.html:41 msgid "IKE Policies" @@ -10396,7 +10434,7 @@ msgstr "Політика IKE" #: netbox/navigation/menu.py:234 msgid "IPSec Proposals" -msgstr "Пропозиції IPsec" +msgstr "Налаштування IPsec" #: netbox/navigation/menu.py:235 templates/vpn/ipsecproposal.html:37 msgid "IPSec Policies" @@ -10407,10 +10445,6 @@ msgstr "Політика IPsec" msgid "IPSec Profiles" msgstr "Профілі IPsec" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "Віртуалізація" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10449,7 +10483,7 @@ msgstr "Провайдери" #: netbox/navigation/menu.py:283 templates/circuits/provider.html:51 msgid "Provider Accounts" -msgstr "Облікові записи постачальника" +msgstr "Облікові записи провайдера" #: netbox/navigation/menu.py:284 msgid "Provider Networks" @@ -10473,7 +10507,7 @@ msgstr "Конфігураційні шаблони" #: netbox/navigation/menu.py:319 netbox/navigation/menu.py:323 msgid "Customization" -msgstr "Налаштування" +msgstr "Персоналізація" #: netbox/navigation/menu.py:325 templates/dcim/device_edit.html:103 #: templates/dcim/htmx/cable_edit.html:81 @@ -10533,7 +10567,7 @@ msgstr "Завдання" #: netbox/navigation/menu.py:371 msgid "Logging" -msgstr "Лісозаготівля" +msgstr "Ведення журналу" #: netbox/navigation/menu.py:373 msgid "Notification Groups" @@ -10611,22 +10645,22 @@ msgid "" "{template_extension} is not a subclass of " "netbox.plugins.PluginTemplateExtension!" msgstr "" -"{template_extension} не є підкласом Netbox.Plugins.PluginTemplateExtension!" +"{template_extension} не є підкласом netbox.plugins.PluginTemplateExtension!" #: netbox/plugins/registration.py:51 #, python-brace-format msgid "{item} must be an instance of netbox.plugins.PluginMenuItem" -msgstr "{item} повинен бути екземпляром Netbox.Plugins.PluginMenuItem" +msgstr "{item} повинен бути екземпляром netbox.plugins.PluginMenuItem" #: netbox/plugins/registration.py:62 #, python-brace-format msgid "{menu_link} must be an instance of netbox.plugins.PluginMenuItem" -msgstr "{menu_link} повинен бути екземпляром Netbox.Plugins.PluginMenuItem" +msgstr "{menu_link} повинен бути екземпляром netbox.plugins.PluginMenuItem" #: netbox/plugins/registration.py:67 #, python-brace-format msgid "{button} must be an instance of netbox.plugins.PluginMenuButton" -msgstr "{button} повинен бути екземпляром Netbox.Plugins.PluginMenuButton" +msgstr "{button} повинен бути екземпляром netbox.plugins.PluginMenuButton" #: netbox/plugins/templates.py:37 msgid "extra_context must be a dictionary" @@ -10642,7 +10676,7 @@ msgstr "Увімкнути динамічну навігацію інтерфе #: netbox/preferences.py:26 msgid "Experimental feature" -msgstr "Експериментальна особливість" +msgstr "Експериментальна функція" #: netbox/preferences.py:29 msgid "Language" @@ -10662,7 +10696,7 @@ msgstr "Довжина сторінки" #: netbox/preferences.py:44 msgid "The default number of objects to display per page" -msgstr "Типова кількість об'єктів для відображення на сторінці" +msgstr "Кількість об'єктів за замовченням на сторінці для відображення" #: netbox/preferences.py:48 msgid "Paginator placement" @@ -10797,7 +10831,7 @@ msgstr "Значення" #: netbox/tests/dummy_plugin/navigation.py:29 msgid "Dummy Plugin" -msgstr "Фікменний плагін" +msgstr "Фіктивний плагін" #: netbox/views/generic/bulk_views.py:114 #, python-brace-format @@ -10813,19 +10847,19 @@ msgstr "" msgid "Row {i}: Object with ID {id} does not exist" msgstr "Ряд {i}: Об'єкт з ідентифікатором {id} не існує" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "Ні {object_type} були обрані." -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "Перейменовано {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "Видалено {count} {object_type}" @@ -10855,9 +10889,9 @@ msgstr "Синхронізовано {count} {object_type}" #: netbox/views/generic/object_views.py:108 #, python-brace-format msgid "{class_name} must implement get_children()" -msgstr "{class_name} повинен реалізувати get_children ()" +msgstr "{class_name} повинен реалізувати get_children()" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -11000,7 +11034,7 @@ msgstr "Замовлення" #: templates/account/preferences.html:51 msgid "Columns" -msgstr "Колони" +msgstr "Колонки" #: templates/account/preferences.html:71 templates/dcim/cable_trace.html:113 #: templates/extras/object_configcontext.html:43 @@ -11060,7 +11094,7 @@ msgstr "Призначені групи" #: templates/users/objectpermission.html:87 templates/users/user.html:58 #: templates/users/user.html:68 msgid "None" -msgstr "Жоден" +msgstr "Жодного" #: templates/account/profile.html:68 templates/users/user.html:78 msgid "Recent Activity" @@ -11074,7 +11108,7 @@ msgstr "Мої жетони API" #: templates/users/token.html:6 templates/users/token.html:14 #: users/forms/filtersets.py:120 msgid "Token" -msgstr "Токен" +msgstr "Жетон" #: templates/account/token.html:39 templates/users/token.html:31 #: users/forms/bulk_edit.py:107 @@ -11087,7 +11121,7 @@ msgstr "Востаннє використано" #: templates/account/token_list.html:12 msgid "Add a Token" -msgstr "Додати токен" +msgstr "Додати Жетон" #: templates/base/base.html:22 templates/home.html:27 msgid "Home" @@ -11142,7 +11176,7 @@ msgstr "Дата припинення" #: templates/circuits/circuit.html:70 #: templates/ipam/inc/panels/fhrp_groups.html:15 msgid "Assign Group" -msgstr "Призначити групу" +msgstr "Призначити у групу" #: templates/circuits/circuit_terminations_swap.html:4 msgid "Swap Circuit Terminations" @@ -11151,7 +11185,7 @@ msgstr "Поміняти місцями кінці каналу зв'язку" #: templates/circuits/circuit_terminations_swap.html:8 #, python-format msgid "Swap these terminations for circuit %(circuit)s?" -msgstr "Поміняти місцями кінці для каналу зв'язку%(circuit)s?" +msgstr "Поміняти місцями кінці для каналу зв'язку %(circuit)s?" #: templates/circuits/circuit_terminations_swap.html:14 msgid "A side" @@ -11199,7 +11233,7 @@ msgstr "Редагувати" #: templates/circuits/inc/circuit_termination.html:18 msgid "Swap" -msgstr "Обмін" +msgstr "Поміняти місцями" #: templates/circuits/inc/circuit_termination_fields.html:19 #: templates/dcim/consoleport.html:59 templates/dcim/consoleserverport.html:60 @@ -11482,7 +11516,7 @@ msgstr "Деталі плагіна" #: templates/core/plugin.html:58 msgid "Summary" -msgstr "У підсумку" +msgstr "Підсумок" #: templates/core/plugin.html:76 msgid "License" @@ -11516,11 +11550,11 @@ msgstr "Зупинити" #: templates/core/rq_task.html:34 msgid "Requeue" -msgstr "Реквье" +msgstr "Повторно поставлено у чергу" #: templates/core/rq_task.html:39 msgid "Enqueue" -msgstr "Поставте в чергу" +msgstr "Поставлено у чергу" #: templates/core/rq_task.html:61 msgid "Queue" @@ -11528,7 +11562,7 @@ msgstr "Черга" #: templates/core/rq_task.html:65 msgid "Timeout" -msgstr "Тайм-аут" +msgstr "Час очікування" #: templates/core/rq_task.html:69 msgid "Result TTL" @@ -11566,9 +11600,7 @@ msgstr "Завдання у черзі" #, python-format msgid "" "Select all %(count)s %(object_type_plural)s matching query" -msgstr "" -"Вибрати усі %(count)s %(object_type_plural)s відповідний " -"запит" +msgstr "Вибрати усі %(count)s %(object_type_plural)s запити" #: templates/core/rq_worker.html:10 msgid "Worker Info" @@ -11621,7 +11653,7 @@ msgstr "Статус системи" #: templates/core/system.html:31 msgid "NetBox release" -msgstr "Випуск NetBox" +msgstr "NetBox реліз" #: templates/core/system.html:44 msgid "Django version" @@ -11721,7 +11753,7 @@ msgstr "Пункт призначення" #: templates/dcim/cable_trace.html:91 msgid "Segments" -msgstr "сегменти" +msgstr "Сегменти" #: templates/dcim/cable_trace.html:104 msgid "Incomplete" @@ -11766,12 +11798,12 @@ msgstr "Переглянути віртуальне шасі" #: templates/dcim/device.html:164 msgid "Create VDC" -msgstr "Створіть джерело живлення постійного струму " +msgstr "Створіть джерело живлення постійного струму" #: templates/dcim/device.html:175 templates/dcim/device_edit.html:64 #: virtualization/forms/model_forms.py:223 msgid "Management" -msgstr "Менеджмент" +msgstr "Керування" #: templates/dcim/device.html:195 templates/dcim/device.html:211 #: templates/dcim/device.html:227 @@ -11811,7 +11843,7 @@ msgstr "ВА" #: templates/dcim/device.html:280 msgctxt "Leg of a power feed" msgid "Leg" -msgstr "Нога" +msgstr "Гілка (електричного кола)" #: templates/dcim/device.html:306 #: templates/virtualization/virtualmachine.html:158 @@ -11844,19 +11876,19 @@ msgstr "Додати передні порти" #: templates/dcim/device/inc/interface_table_controls.html:9 msgid "Hide Enabled" -msgstr "Приховати увімкнено" +msgstr "Приховати усе, що увімкнено" #: templates/dcim/device/inc/interface_table_controls.html:10 msgid "Hide Disabled" -msgstr "Приховати вимкнено" +msgstr "Приховати усе, що вимкнено" #: templates/dcim/device/inc/interface_table_controls.html:11 msgid "Hide Virtual" -msgstr "Приховати віртуальний" +msgstr "Приховати усе, що має віртуальне походження" #: templates/dcim/device/inc/interface_table_controls.html:12 msgid "Hide Disconnected" -msgstr "Приховати відключене" +msgstr "Приховати усе, що відключене" #: templates/dcim/device/interfaces.html:27 msgid "Add Interfaces" @@ -11886,7 +11918,7 @@ msgstr "Додати задні порти" #: templates/dcim/device/render_config.html:5 #: templates/virtualization/virtualmachine/render_config.html:5 msgid "Config" -msgstr "конфігурація" +msgstr "Конфігурація" #: templates/dcim/device/render_config.html:35 #: templates/virtualization/virtualmachine/render_config.html:35 @@ -11910,12 +11942,12 @@ msgstr "Не знайдено шаблону конфігурації" #: templates/dcim/device_edit.html:44 msgid "Parent Bay" -msgstr "Батьківська бухта" +msgstr "Батьківський відсік" #: templates/dcim/device_edit.html:48 #: utilities/templates/form_helpers/render_field.html:22 msgid "Regenerate Slug" -msgstr "Відновити слимака" +msgstr "Відновити скорочення" #: templates/dcim/device_edit.html:49 templates/generic/bulk_remove.html:21 #: utilities/templates/helpers/table_config_form.html:23 @@ -11934,7 +11966,7 @@ msgstr "Перейменувати" #: templates/dcim/devicebay.html:17 msgid "Device Bay" -msgstr "Резервуар для пристроїв" +msgstr "Відсік для пристроїв" #: templates/dcim/devicebay.html:43 msgid "Installed Device" @@ -11956,11 +11988,11 @@ msgstr "" #: templates/dcim/devicebay_populate.html:13 msgid "Populate" -msgstr "Заселити" +msgstr "Заповнити" #: templates/dcim/devicebay_populate.html:22 msgid "Bay" -msgstr "затока" +msgstr "Відсік" #: templates/dcim/devicerole.html:14 templates/dcim/platform.html:17 msgid "Add Device" @@ -11984,7 +12016,7 @@ msgstr "Виключити з використання" #: templates/dcim/devicetype.html:59 msgid "Parent/Child" -msgstr "Батька/Дитина" +msgstr "Батько/Дитина" #: templates/dcim/devicetype.html:71 msgid "Front Image" @@ -11992,11 +12024,11 @@ msgstr "Зображення спереду" #: templates/dcim/devicetype.html:83 msgid "Rear Image" -msgstr "Ззаднє зображення" +msgstr "Зображення ззаду" #: templates/dcim/frontport.html:54 msgid "Rear Port Position" -msgstr "Положення заднього порту" +msgstr "Положення порту ззаду" #: templates/dcim/frontport.html:72 templates/dcim/interface.html:144 #: templates/dcim/poweroutlet.html:63 templates/dcim/powerport.html:63 @@ -12018,11 +12050,11 @@ msgstr "Сторона Б" #: templates/dcim/inc/cable_termination.html:65 msgid "No termination" -msgstr "Без припинення" +msgstr "Без кінця" #: templates/dcim/inc/cable_toggle_buttons.html:3 msgid "Mark Planned" -msgstr "Марк Планований" +msgstr "Позначка запланова" #: templates/dcim/inc/cable_toggle_buttons.html:6 msgid "Mark Installed" @@ -12051,12 +12083,12 @@ msgstr "Без позначки" #: templates/dcim/inc/interface_vlans_table.html:37 msgid "No VLANs Assigned" -msgstr "Не присвоєно VLAN" +msgstr "Не присвоєно VLAN'ів" #: templates/dcim/inc/interface_vlans_table.html:44 #: templates/ipam/prefix_list.html:16 templates/ipam/prefix_list.html:33 msgid "Clear" -msgstr "Прозорий" +msgstr "Очистити" #: templates/dcim/inc/interface_vlans_table.html:47 msgid "Clear All" @@ -12068,7 +12100,7 @@ msgstr "Глибина монтажу" #: templates/dcim/inc/panels/racktype_numbering.html:6 msgid "Starting Unit" -msgstr "Пусковий блок" +msgstr "Початковий юніт" #: templates/dcim/inc/panels/racktype_numbering.html:10 msgid "Descending Units" @@ -12106,7 +12138,7 @@ msgstr "MAC-адреса" #: templates/dcim/interface.html:151 msgid "Wireless Link" -msgstr "Бездротове посилання" +msgstr "Бездротове з'єднання" #: templates/dcim/interface.html:218 vpn/choices.py:55 msgid "Peer" @@ -12115,7 +12147,7 @@ msgstr "Мережевий сусід" #: templates/dcim/interface.html:230 #: templates/wireless/inc/wirelesslink_interface.html:26 msgid "Channel" -msgstr "канал" +msgstr "Канал" #: templates/dcim/interface.html:239 #: templates/wireless/inc/wirelesslink_interface.html:32 @@ -12169,7 +12201,7 @@ msgstr "Додати підпорядковане місцезнаходженн #: templates/dcim/location.html:77 msgid "Child Locations" -msgstr "Підпорядковані локації" +msgstr "Підпорядковані місцезнаходження" #: templates/dcim/location.html:81 templates/dcim/site.html:131 msgid "Add a Location" @@ -12177,7 +12209,7 @@ msgstr "Додати місцезнаходження" #: templates/dcim/location.html:94 templates/dcim/site.html:144 msgid "Add a Device" -msgstr "Додавання пристрою" +msgstr "Додати пристрою" #: templates/dcim/manufacturer.html:16 msgid "Add Device Type" @@ -12202,7 +12234,7 @@ msgstr "Електричні характеристики" #: templates/dcim/powerfeed.html:88 msgctxt "Abbreviation for volts" msgid "V" -msgstr "V" +msgstr "В" #: templates/dcim/powerfeed.html:92 msgctxt "Abbreviation for amperes" @@ -12342,7 +12374,7 @@ msgstr "Додати учасника" #: templates/dcim/virtualchassis_add.html:18 msgid "Member Devices" -msgstr "Пристрої членів" +msgstr "Учасника пристроїв" #: templates/dcim/virtualchassis_add_member.html:10 #, python-format @@ -12375,7 +12407,7 @@ msgstr "Стійка/юніт" #: templates/dcim/virtualchassis_remove_member.html:5 msgid "Remove Virtual Chassis Member" -msgstr "Вилучити віртуальний член шасі" +msgstr "Вилучити віртуального учасника шасі" #: templates/dcim/virtualchassis_remove_member.html:9 #, python-format @@ -12412,11 +12444,11 @@ msgid "" "of required packages." msgstr "" "У цій інсталяції NetBox може бути відсутній один або кілька необхідних " -"пакетів Python. Ці пакети перераховані в requirements.txt і " +"пакетів Python. Ці пакети перераховані в requirements.txt та " "local_requirements.txt, і зазвичай встановлюються як частина " "процесу встановлення або оновлення. Щоб перевірити встановлені пакети, " -"запустіть заморожування піп з консолі і порівняйте вихід зі " -"списком необхідних пакетів." +"запустіть pip freeze з консолі і порівняйте вихід зі списком " +"необхідних пакетів." #: templates/exceptions/import_error.html:20 msgid "WSGI service not restarted after upgrade" @@ -12459,8 +12491,8 @@ msgid "" "A database programming error was detected while processing this request. " "Common causes include the following:" msgstr "" -"Під час обробки цього запиту була виявлена помилка програмування бази даних." -" До поширених причин можна віднести наступне:" +"Під час обробки цього запиту була виявлена програмна помилка бази даних. До " +"поширених причин можна віднести наступне:" #: templates/exceptions/programming_error.html:10 msgid "Database migrations missing" @@ -12501,7 +12533,7 @@ msgstr "Файл даних, пов'язаний з цим об'єктом, ви #: templates/extras/configtemplate.html:46 #: templates/extras/exporttemplate.html:60 msgid "Data Synced" -msgstr "Синхронізовані дані" +msgstr "Дані синхронізовані" #: templates/extras/configcontext_list.html:7 #: templates/extras/configtemplate_list.html:7 @@ -12588,7 +12620,7 @@ msgid "" "This will remove all configured widgets and restore the " "default dashboard configuration." msgstr "" -"Це видалить усі налаштовані віджети та відновити " +"Це видалить усі налаштовані віджети та відновить " "конфігурацію інформаційної панелі за замовчуванням." #: templates/extras/dashboard/reset.html:13 @@ -12714,46 +12746,51 @@ msgid "You do not have permission to run scripts" msgstr "У вас немає дозволу на запуск скриптів" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "Запустити скрипт" #: templates/extras/script.html:51 templates/extras/script/source.html:10 msgid "Error loading script" -msgstr "Помилка завантаження сценарію" +msgstr "Помилка завантаження скрипту" #: templates/extras/script/jobs.html:16 msgid "Script no longer exists in the source file." msgstr "Скрипт більше не існує у вихідному файлі." -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "Останній запуск" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "Скрипт більше не присутній у вихідному файлі" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "Ніколи" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "Запустіть знову" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "Не вдалося завантажити скрипти з модуля %(module)s" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "Скриптів не знайдено" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " "an uploaded file or data source." msgstr "" "Почніть з створення сценарію з " -"завантаженого файлу або джерела даних." +"вивантаженого файлу або джерела даних." #: templates/extras/script_result.html:35 #: templates/generic/object_list.html:50 templates/search.html:13 @@ -12806,7 +12843,7 @@ msgstr "Додаткові заголовки" #: templates/extras/webhook.html:70 msgid "Body Template" -msgstr "Шаблон тіла" +msgstr "Шаблон тіла (запросу)" #: templates/generic/bulk_add_component.html:29 msgid "Bulk Creation" @@ -12861,7 +12898,7 @@ msgstr "Прямий імпорт" #: templates/generic/bulk_import.html:30 msgid "Upload File" -msgstr "Завантажити файл" +msgstr "Вивантажити файл" #: templates/generic/bulk_import.html:58 templates/generic/bulk_import.html:80 #: templates/generic/bulk_import.html:102 @@ -12882,7 +12919,7 @@ msgstr "вибір" #: templates/generic/bulk_import.html:161 msgid "Import Value" -msgstr "Імпортна вартість" +msgstr "Імпорт вартості" #: templates/generic/bulk_import.html:181 msgid "Format: YYYY-MM-DD" @@ -12904,7 +12941,7 @@ msgid "" "%(example)s would identify a VRF by its route distinguisher." msgstr "" "Пов'язані об'єкти можуть посилатися будь-яким унікальним атрибутом. " -"Наприклад, %(example)s ідентифікує VRF за його визначником " +"Наприклад, %(example)s ідентифікує VRF за його розрізнювачем " "маршруту." #: templates/generic/bulk_remove.html:28 @@ -12981,7 +13018,7 @@ msgstr "Переглянути документацію моделі" #: templates/generic/object_edit.html:36 msgid "Help" -msgstr "Допоможіть" +msgstr "Підказка" #: templates/generic/object_edit.html:83 msgid "Create & Add Another" @@ -13002,7 +13039,7 @@ msgstr "" #: templates/home.html:15 msgid "New Release Available" -msgstr "Новий випуск доступний" +msgstr "Новий реліз доступний" #: templates/home.html:16 msgid "is available" @@ -13019,7 +13056,7 @@ msgstr "Розблокування інформаційної панелі" #: templates/home.html:49 msgid "Lock Dashboard" -msgstr "Блокування інформаційної панелі " +msgstr "Блокування інформаційної панелі" #: templates/home.html:60 msgid "Add Widget" @@ -13081,7 +13118,7 @@ msgid "" "Before you can add a %(model)s you must first create a " "%(prerequisite_model)s." msgstr "" -"Перш ніж ви зможете додати %(model)s спочатку потрібно створити " +"Перш ніж ви зможете додати %(model)s, спочатку потрібно створити " "%(prerequisite_model)s." #: templates/inc/paginator.html:15 @@ -13091,7 +13128,7 @@ msgstr "Вибір сторінки" #: templates/inc/paginator.html:75 #, python-format msgid "Showing %(start)s-%(end)s of %(total)s" -msgstr "Показуючи %(start)s-%(end)s з %(total)s" +msgstr "Показ %(start)s-%(end)s із %(total)s" #: templates/inc/paginator.html:82 msgid "Pagination options" @@ -13135,7 +13172,7 @@ msgstr "Довідковий центр" #: templates/inc/user_menu.html:41 msgid "Django Admin" -msgstr "Джанго Адміністратор" +msgstr "Адміністратор Django" #: templates/inc/user_menu.html:61 msgid "Log Out" @@ -13246,7 +13283,7 @@ msgstr "Деталі адресації" #: templates/ipam/prefix.html:118 msgid "Child IPs" -msgstr "Дитячі IP-адреси" +msgstr "Підпорядковані IP-адреси" #: templates/ipam/prefix.html:126 msgid "Available IPs" @@ -13274,7 +13311,7 @@ msgstr "Маска підстановки" #: templates/ipam/prefix.html:197 msgid "Broadcast Address" -msgstr "Адреса трансляції" +msgstr "Широкомовна адреса" #: templates/ipam/prefix/ip_ranges.html:7 msgid "Add IP Range" @@ -13306,11 +13343,11 @@ msgstr "Експорт VRF" #: templates/ipam/routetarget.html:52 msgid "Importing L2VPNs" -msgstr "Імпорт L2VPN" +msgstr "Імпорт L2VPN'ів" #: templates/ipam/routetarget.html:58 msgid "Exporting L2VPNs" -msgstr "Експорт L2VPN" +msgstr "Експорт L2VPN'ів" #: templates/ipam/vlan.html:88 msgid "Add a Prefix" @@ -13322,7 +13359,7 @@ msgstr "Додати VLAN" #: templates/ipam/vrf.html:16 msgid "Route Distinguisher" -msgstr "Відмінник маршруту" +msgstr "Розрізнювач маршруту" #: templates/ipam/vrf.html:29 msgid "Unique IP Space" @@ -13344,11 +13381,11 @@ msgstr "Або" #: templates/media_failure.html:7 msgid "Static Media Failure - NetBox" -msgstr "Помилка статичного носія - NetBox" +msgstr "Помилка статичних медіа-файлів - NetBox" #: templates/media_failure.html:21 msgid "Static Media Failure" -msgstr "Помилка статичного носія" +msgstr "Помилка статичних медіа-файлів" #: templates/media_failure.html:23 msgid "The following static media file failed to load" @@ -13364,7 +13401,7 @@ msgid "" " This installs the most recent iteration of each static file into the static" " root path." msgstr "" -"manage.py колективстатичний було запущено під час останнього " +"manage.py collectstatic було запущено під час останнього " "оновлення. Це встановлює останню ітерацію кожного статичного файлу в " "статичний кореневий шлях." @@ -13553,18 +13590,18 @@ msgstr "Попередньо спільний ключ" #: templates/vpn/ikepolicy.html:33 #: templates/wireless/inc/authentication_attrs.html:20 msgid "Show Secret" -msgstr "Показати Таємницю" +msgstr "Показати таємницю" #: templates/vpn/ikepolicy.html:57 templates/vpn/ipsecpolicy.html:45 #: templates/vpn/ipsecprofile.html:52 templates/vpn/ipsecprofile.html:77 #: vpn/forms/model_forms.py:316 vpn/forms/model_forms.py:352 #: vpn/tables/crypto.py:68 vpn/tables/crypto.py:134 msgid "Proposals" -msgstr "Пропозиції" +msgstr "Налаштування" #: templates/vpn/ikeproposal.html:10 msgid "IKE Proposal" -msgstr "Пропозиція IKE" +msgstr "Налаштування IKE" #: templates/vpn/ikeproposal.html:21 vpn/forms/bulk_edit.py:97 #: vpn/forms/bulk_import.py:145 vpn/forms/filtersets.py:101 @@ -13602,7 +13639,7 @@ msgstr "Політика IPsec" #: templates/vpn/ipsecpolicy.html:21 vpn/forms/bulk_edit.py:210 #: vpn/models/crypto.py:193 msgid "PFS group" -msgstr "Група ПФС" +msgstr "Група PFS" #: templates/vpn/ipsecprofile.html:10 vpn/forms/model_forms.py:54 msgid "IPSec Profile" @@ -13610,7 +13647,7 @@ msgstr "Профіль IPsec" #: templates/vpn/ipsecprofile.html:89 vpn/tables/crypto.py:137 msgid "PFS Group" -msgstr "Група ПФС" +msgstr "Група PFS" #: templates/vpn/ipsecproposal.html:10 msgid "IPSec Proposal" @@ -13627,11 +13664,11 @@ msgstr "L2VPN Атрибути" #: templates/vpn/l2vpn.html:60 templates/vpn/tunnel.html:76 msgid "Add a Termination" -msgstr "Додати припинення" +msgstr "Додати кінець" #: templates/vpn/tunnel.html:9 msgid "Add Termination" -msgstr "Додати припинення" +msgstr "Додати кінець" #: templates/vpn/tunnel.html:37 vpn/forms/bulk_edit.py:49 #: vpn/forms/bulk_import.py:48 vpn/forms/filtersets.py:57 @@ -13660,7 +13697,7 @@ msgstr "Тунельна група" #: templates/vpn/tunneltermination.html:10 msgid "Tunnel Termination" -msgstr "Закриття тунелю" +msgstr "Кінець тунелю" #: templates/vpn/tunneltermination.html:35 vpn/forms/bulk_import.py:107 #: vpn/forms/model_forms.py:102 vpn/forms/model_forms.py:138 @@ -13678,7 +13715,7 @@ msgstr "Шифр" #: templates/wireless/inc/authentication_attrs.html:16 msgid "PSK" -msgstr " Попередньо спільний ключ (PSK)" +msgstr "Попередньо спільний ключ (PSK)" #: templates/wireless/inc/wirelesslink_interface.html:35 #: templates/wireless/inc/wirelesslink_interface.html:45 @@ -13692,7 +13729,7 @@ msgstr "Прикріплені інтерфейси" #: templates/wireless/wirelesslangroup.html:17 msgid "Add Wireless LAN" -msgstr "Додати бездротову мережу" +msgstr "Додати бездротову локальну мережу" #: templates/wireless/wirelesslangroup.html:26 #: wireless/forms/model_forms.py:28 @@ -13718,7 +13755,7 @@ msgstr "Батьківська контактна група (ідентифік #: tenancy/filtersets.py:34 msgid "Parent contact group (slug)" -msgstr "Батьківська контактна група (скоречення)" +msgstr "Батьківська контактна група (скорочення)" #: tenancy/filtersets.py:40 tenancy/filtersets.py:67 tenancy/filtersets.py:110 msgid "Contact group (ID)" @@ -13726,7 +13763,7 @@ msgstr "Контактна група (ідентифікатор)" #: tenancy/filtersets.py:47 tenancy/filtersets.py:74 tenancy/filtersets.py:117 msgid "Contact group (slug)" -msgstr "Контактна група (скоречення)" +msgstr "Контактна група (скорочення)" #: tenancy/filtersets.py:104 msgid "Contact (ID)" @@ -13738,7 +13775,7 @@ msgstr "Роль контакту (ідентифікатор)" #: tenancy/filtersets.py:127 msgid "Contact role (slug)" -msgstr "Контактна роль (скоречення)" +msgstr "Контактна роль (скорочення)" #: tenancy/filtersets.py:158 msgid "Contact group" @@ -13750,7 +13787,7 @@ msgstr "Батьківська група орендарів (ідентифік #: tenancy/filtersets.py:175 msgid "Parent tenant group (slug)" -msgstr "Батьківська група орендарів (скоречення)" +msgstr "Батьківська група орендарів (скорочення)" #: tenancy/filtersets.py:181 tenancy/filtersets.py:201 msgid "Tenant group (ID)" @@ -13762,7 +13799,7 @@ msgstr "Група орендарів (ідентифікатор)" #: tenancy/filtersets.py:241 msgid "Tenant Group (slug)" -msgstr "Група орендарів (скоречення)" +msgstr "Група орендарів (скорочення)" #: tenancy/forms/bulk_edit.py:66 msgid "Desciption" @@ -13814,11 +13851,11 @@ msgstr "контакти" #: tenancy/models/contacts.py:153 msgid "contact assignment" -msgstr "призначення контактів" +msgstr "призначення контакта" #: tenancy/models/contacts.py:154 msgid "contact assignments" -msgstr "контактні завдання" +msgstr "призначення контакта" #: tenancy/models/contacts.py:170 #, python-brace-format @@ -13839,7 +13876,7 @@ msgstr "Ім'я орендаря має бути унікальним для к #: tenancy/models/tenants.py:80 msgid "Tenant slug must be unique per group." -msgstr "Слимак орендаря повинен бути унікальним для кожної групи." +msgstr "Скоречення орендаря повинен бути унікальним для кожної групи." #: tenancy/models/tenants.py:88 msgid "tenant" @@ -13847,7 +13884,7 @@ msgstr "орендар" #: tenancy/models/tenants.py:89 msgid "tenants" -msgstr "орендарів" +msgstr "орендарі" #: tenancy/tables/contacts.py:112 msgid "Contact Title" @@ -13855,19 +13892,19 @@ msgstr "Назва контакту" #: tenancy/tables/contacts.py:116 msgid "Contact Phone" -msgstr "Контактний телефон" +msgstr "Телефон контакту" #: tenancy/tables/contacts.py:121 msgid "Contact Email" -msgstr "Контактна адреса електронної скриньки" +msgstr "Контактний Email" #: tenancy/tables/contacts.py:125 msgid "Contact Address" -msgstr "Контактна адреса" +msgstr "Адреса контакту" #: tenancy/tables/contacts.py:129 msgid "Contact Link" -msgstr "Посилання на контакт" +msgstr "Посилання контакту" #: tenancy/tables/contacts.py:133 msgid "Contact Description" @@ -13903,7 +13940,7 @@ msgstr "Якщо ключ не надано, він буде згенерова #: users/forms/filtersets.py:51 users/tables.py:42 msgid "Is Staff" -msgstr "Чи є персонал" +msgstr "Є персоналом" #: users/forms/filtersets.py:58 users/tables.py:45 msgid "Is Superuser" @@ -13946,8 +13983,8 @@ msgid "" "10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64" msgstr "" "Дозволені мережі IPv4/IPv6, звідки можна використовувати токен. Залиште " -"порожнім без обмежень. Приклад: 10.1.1.0/24,192.168.10.16/32,2001: дб " -"8:1: :/64" +"порожнім без обмежень. Приклад: " +"10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64" #: users/forms/model_forms.py:175 msgid "Confirm password" @@ -14061,11 +14098,11 @@ msgid "" msgstr "" "Дозволені мережі IPv4/IPv6, звідки можна використовувати жетон. Залиште " "порожнім без обмежень. Наприклад: \"10.1.1.0/24, 192.168.10.16/32, " -"2001:DB8:1: :/64\"" +"2001:DB8:1::/64\"" #: users/models/tokens.py:75 msgid "token" -msgstr "токен" +msgstr "жетон" #: users/models/tokens.py:76 msgid "tokens" @@ -14117,16 +14154,16 @@ msgstr "" #: utilities/choices.py:19 #, python-brace-format msgid "{name} has a key defined but CHOICES is not a list" -msgstr "{name} має визначений ключ, але CHOICES не є списком" +msgstr "{name} має визначений ключ, але ВИБІР не є списком" #: utilities/conversion.py:19 msgid "Weight must be a positive number" -msgstr "Вага повинна бути позитивним числом" +msgstr "Вага повинна бути додатним числом" #: utilities/conversion.py:21 #, python-brace-format msgid "Invalid value '{weight}' for weight (must be a number)" -msgstr "Невірне значення '{weight}'для ваги (має бути число)" +msgstr "Невірне значення '{weight}' для ваги (має бути число)" #: utilities/conversion.py:32 utilities/conversion.py:62 #, python-brace-format @@ -14140,7 +14177,7 @@ msgstr "Довжина повинна бути додатним числом" #: utilities/conversion.py:47 #, python-brace-format msgid "Invalid value '{length}' for length (must be a number)" -msgstr "Невірне значення '{length}'для довжини (має бути число)" +msgstr "Невірне значення '{length}' для довжини (має бути число)" #: utilities/error_handlers.py:31 #, python-brace-format @@ -14165,7 +14202,7 @@ msgid "" "%s(%r) is invalid. to_model parameter to CounterCacheField must be a string " "in the format 'app.model'" msgstr "" -"%s(%r) невырний. Параметр to_model до CounterCacheField повинен бути рядком " +"%s(%r) невірний. Параметр to_model до CounterCacheField повинен бути рядком " "у форматі 'app.model'" #: utilities/fields.py:169 @@ -14191,7 +14228,7 @@ msgstr "Символ, який розмежовує поля CSV. Застосо #: utilities/forms/bulk_import.py:51 msgid "Form data must be empty when uploading/selecting a file." -msgstr "Дані форми повинні бути порожніми під час завантаження/вибору файлу." +msgstr "Дані форми повинні бути порожніми під час вивантаження/вибору файлу." #: utilities/forms/bulk_import.py:80 #, python-brace-format @@ -14279,7 +14316,7 @@ msgid "" msgstr "" "Буквено-цифрові діапазони підтримуються для масового створення. Змішані " "відмінки і типи в межах одного діапазону не підтримуються (приклад: " -"[Ге, хе] -0/0/ [0-9])." +"[ge,xe]-0/0/[0-9])." #: utilities/forms/fields/expandable.py:46 msgid "" @@ -14287,7 +14324,7 @@ msgid "" "192.0.2.[1,5,100-254]/24" msgstr "" "Вкажіть числовий діапазон для створення декількох IP-адрес.
    Приклад: " -"192.0.2. [1,5100-254] /24" +"192.0.2.[1,5,100-254]/24" #: utilities/forms/fields/fields.py:31 #, python-brace-format @@ -14328,7 +14365,7 @@ msgstr "Нерозпізнаний заголовок: {name}" #: utilities/forms/forms.py:118 msgid "Available Columns" -msgstr "Доступні колонки" +msgstr "Доступні стовпці" #: utilities/forms/forms.py:126 msgid "Selected Columns" @@ -14382,7 +14419,8 @@ msgstr "Знайдено несподіваний заголовок стовп #, python-brace-format msgid "Column \"{field}\" is not a related object; cannot use dots" msgstr "" -"Колонка \"{field}\" не є спорідненим об'єктом; не може використовувати точки" +"Стовпчик \"{field}\" не є спорідненим об'єктом; не може використовувати " +"точки" #: utilities/forms/utils.py:276 #, python-brace-format @@ -14498,11 +14536,11 @@ msgstr "Копіювати в буфер обміну" #: utilities/templates/form_helpers/render_field.html:57 msgid "This field is required" -msgstr "Це поле обов'язкове для заповнення" +msgstr "Це обов'язкове поле для заповнення" #: utilities/templates/form_helpers/render_field.html:70 msgid "Set Null" -msgstr "Встановити нуль" +msgstr "Встановити нуль (Null)" #: utilities/templates/helpers/applied_filters.html:11 msgid "Clear all" @@ -14514,15 +14552,15 @@ msgstr "Налаштування таблиці" #: utilities/templates/helpers/table_config_form.html:31 msgid "Move Up" -msgstr "Рухатися вгору" +msgstr "Рухати угору" #: utilities/templates/helpers/table_config_form.html:34 msgid "Move Down" -msgstr "Рухатися вниз" +msgstr "Рухати вниз" #: utilities/templates/navigation/menu.html:14 msgid "Search…" -msgstr "Пошук..." +msgstr "Пошук…" #: utilities/templates/navigation/menu.html:14 msgid "Search NetBox" @@ -14554,7 +14592,7 @@ msgstr "" #: utilities/views.py:93 #, python-brace-format msgid "{class_name} must implement get_required_permission()" -msgstr "{class_name} повинен реалізувати get_required_permissions ()" +msgstr "{class_name} повинен реалізувати get_required_permissions()" #: utilities/views.py:117 #, python-brace-format @@ -14572,7 +14610,7 @@ msgstr "Батьківська група (ідентифікатор)" #: virtualization/filtersets.py:85 msgid "Parent group (slug)" -msgstr "Батьківська група (скоречення)" +msgstr "Батьківська група (скорочення)" #: virtualization/filtersets.py:89 virtualization/filtersets.py:141 msgid "Cluster type (ID)" @@ -14592,13 +14630,13 @@ msgid "Memory (MB)" msgstr "Пам'ять (МБ)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "Диск (ГБ)" +msgid "Disk (MB)" +msgstr "Диск (МБ)" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "Розмір (ГБ)" +msgid "Size (MB)" +msgstr "Розмір (МБ)" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" @@ -14739,7 +14777,7 @@ msgstr "" #: virtualization/models/virtualmachines.py:229 #, python-brace-format msgid "Must be an IPv{family} address. ({ip} is an IPv{version} address.)" -msgstr "Повинен бути IPV{family} адреса. ({ip} є IPV{version} адреса.)" +msgstr "Повинен бути IPv{family} адреса. ({ip} є IPv{version} адреса.)" #: virtualization/models/virtualmachines.py:238 #, python-brace-format @@ -14789,12 +14827,12 @@ msgstr "віртуальні диски" #: virtualization/views.py:275 #, python-brace-format msgid "Added {count} devices to cluster {cluster}" -msgstr "Додано {count} пристрої для кластеризації {cluster}" +msgstr "Додано {count} пристроїв для кластеризації {cluster}" #: virtualization/views.py:310 #, python-brace-format msgid "Removed {count} devices from cluster {cluster}" -msgstr "Вилучено {count} пристрої з кластера {cluster}" +msgstr "Вилучено {count} пристроїв з кластера {cluster}" #: vpn/choices.py:31 msgid "IPsec - Transport" @@ -14806,11 +14844,11 @@ msgstr "IPsec - тунель" #: vpn/choices.py:33 msgid "IP-in-IP" -msgstr "IP-адреси в IP" +msgstr "IP-в-IP" #: vpn/choices.py:34 msgid "GRE" -msgstr "ГРЕ" +msgstr "GRE" #: vpn/choices.py:56 msgid "Hub" @@ -14818,11 +14856,11 @@ msgstr "Хаб" #: vpn/choices.py:57 msgid "Spoke" -msgstr "говорив" +msgstr "Спиця (в колесі)" #: vpn/choices.py:80 msgid "Aggressive" -msgstr "Агресивний" +msgstr "Агресивно" #: vpn/choices.py:81 msgid "Main" @@ -14876,7 +14914,7 @@ msgstr "Тунельна група (ідентифікатор)" #: vpn/filtersets.py:47 msgid "Tunnel group (slug)" -msgstr "Тунельна група (скоречення)" +msgstr "Тунельна група (скорочення)" #: vpn/filtersets.py:54 msgid "IPSec profile (ID)" @@ -14916,7 +14954,7 @@ msgstr "Політика IPsec (назва)" #: vpn/filtersets.py:348 msgid "L2VPN (slug)" -msgstr "L2VPN (скоречення)" +msgstr "L2VPN (скорочення)" #: vpn/filtersets.py:412 msgid "VM Interface (ID)" @@ -14975,15 +15013,15 @@ msgstr "Інтерфейс пристрою або віртуальної маш #: vpn/forms/bulk_import.py:183 msgid "IKE proposal(s)" -msgstr "Пропозиція (и) IKE" +msgstr "Пропозиція/iї IKE" #: vpn/forms/bulk_import.py:215 vpn/models/crypto.py:197 msgid "Diffie-Hellman group for Perfect Forward Secrecy" -msgstr "Група Діффі-Хеллмана для «Ідеальна таємниця вперед»" +msgstr "Група Діффі-Хеллмана для Perfect Forward Secrecy" #: vpn/forms/bulk_import.py:222 msgid "IPSec proposal(s)" -msgstr "Пропозиція (и) IPsec" +msgstr "Пропозиція/iї IPsec" #: vpn/forms/bulk_import.py:236 msgid "IPSec protocol" @@ -15039,15 +15077,15 @@ msgstr "Інтерфейс тунелю" #: vpn/forms/model_forms.py:150 msgid "First Termination" -msgstr "Перше припинення" +msgstr "Перший кінець" #: vpn/forms/model_forms.py:153 msgid "Second Termination" -msgstr "Друге припинення" +msgstr "Другий кінець" #: vpn/forms/model_forms.py:197 msgid "This parameter is required when defining a termination." -msgstr "Цей параметр обов'язковий при визначенні закінчення." +msgstr "Цей параметр обов'язковий при визначенні кінця." #: vpn/forms/model_forms.py:320 vpn/forms/model_forms.py:356 msgid "Policy" @@ -15055,13 +15093,12 @@ msgstr "Політика" #: vpn/forms/model_forms.py:487 msgid "A termination must specify an interface or VLAN." -msgstr "Припинення повинно вказувати інтерфейс або VLAN." +msgstr "Кінець повинен підключатися до інтерфейсу або VLAN." #: vpn/forms/model_forms.py:489 msgid "" "A termination can only have one terminating object (an interface or VLAN)." -msgstr "" -"Термінування може мати лише один кінцевий об'єкт (інтерфейс або VLAN)." +msgstr "Кінець може мати лише один кінцевий об'єкт (інтерфейс або VLAN)." #: vpn/models/crypto.py:33 msgid "encryption algorithm" @@ -15085,7 +15122,7 @@ msgstr "Пропозиція IKE" #: vpn/models/crypto.py:60 msgid "IKE proposals" -msgstr "Пропозиції IKE" +msgstr "Налаштування IKE" #: vpn/models/crypto.py:76 msgid "version" @@ -15093,7 +15130,7 @@ msgstr "версія" #: vpn/models/crypto.py:88 vpn/models/crypto.py:190 msgid "proposals" -msgstr "пропозиції" +msgstr "налаштування" #: vpn/models/crypto.py:91 wireless/models.py:39 msgid "pre-shared key" @@ -15149,16 +15186,16 @@ msgstr "Профілі IPsec" #: vpn/models/l2vpn.py:116 msgid "L2VPN termination" -msgstr "Припинення L2VPN" +msgstr "Кінець L2VPN" #: vpn/models/l2vpn.py:117 msgid "L2VPN terminations" -msgstr "Термінації L2VPN" +msgstr "Кінці L2VPN" #: vpn/models/l2vpn.py:135 #, python-brace-format msgid "L2VPN Termination already assigned ({assigned_object})" -msgstr "Припинення L2VPN вже призначено ({assigned_object})" +msgstr "Кінець L2VPN вже призначено ({assigned_object})" #: vpn/models/l2vpn.py:147 #, python-brace-format @@ -15166,7 +15203,7 @@ msgid "" "{l2vpn_type} L2VPNs cannot have more than two terminations; found " "{terminations_count} already defined." msgstr "" -"{l2vpn_type} L2VPN не може мати більше двох термінів; знайдено " +"{l2vpn_type} L2VPN не може мати більше двох кінців; знайдено " "{terminations_count} вже визначено." #: vpn/models/tunnels.py:26 @@ -15195,15 +15232,15 @@ msgstr "тунелі" #: vpn/models/tunnels.py:153 msgid "An object may be terminated to only one tunnel at a time." -msgstr "Об'єкт може бути завершений лише в одному тунелі одночасно." +msgstr "Об'єкт може бути кінцем лише в одному тунелі одночасно." #: vpn/models/tunnels.py:156 msgid "tunnel termination" -msgstr "закінчення тунелю" +msgstr "кинець тунелю" #: vpn/models/tunnels.py:157 msgid "tunnel terminations" -msgstr "закінчення тунелів" +msgstr "кінці тунелів" #: vpn/models/tunnels.py:174 #, python-brace-format @@ -15224,7 +15261,7 @@ msgstr "Алгоритм аутентифікації" #: vpn/tables/crypto.py:34 msgid "SA Lifetime" -msgstr "SA Термін служби" +msgstr "Тривалість життя SA" #: vpn/tables/crypto.py:71 msgid "Pre-shared Key" @@ -15232,11 +15269,11 @@ msgstr "Попередньо спільний ключ" #: vpn/tables/crypto.py:103 msgid "SA Lifetime (Seconds)" -msgstr "Термін служби SA (секунди)" +msgstr "Тривалість життя SA (секунди)" #: vpn/tables/crypto.py:106 msgid "SA Lifetime (KB)" -msgstr "Термін служби SA (КБ)" +msgstr "Тривалість життя SA (КБ)" #: vpn/tables/l2vpn.py:69 msgid "Object Parent" @@ -15244,7 +15281,7 @@ msgstr "Батьківський об'єкт" #: vpn/tables/l2vpn.py:74 msgid "Object Site" -msgstr "Сайт об'єкта" +msgstr "Тех. майданчик об'єкта" #: wireless/choices.py:11 msgid "Access point" @@ -15288,7 +15325,7 @@ msgstr "Інтерфейс A" #: wireless/forms/bulk_import.py:93 wireless/tables/wirelesslink.py:37 msgid "Interface B" -msgstr "Інтерфейс B" +msgstr "Інтерфейс Б" #: wireless/forms/model_forms.py:161 msgid "Side B" @@ -15316,7 +15353,7 @@ msgstr "інтерфейс А" #: wireless/models.py:151 msgid "interface B" -msgstr "інтерфейс B" +msgstr "інтерфейс Б" #: wireless/models.py:165 msgid "distance" @@ -15328,15 +15365,17 @@ msgstr "одиниця відстані" #: wireless/models.py:219 msgid "wireless link" -msgstr "бездротова зв'язок" +msgstr "бездротовий канал зв'язок" #: wireless/models.py:220 msgid "wireless links" -msgstr "бездротові зв'язки" +msgstr "бездротові канали зв'язку" #: wireless/models.py:236 msgid "Must specify a unit when setting a wireless distance" -msgstr "Необхідно вказати одиницю виміру при установці бездротової відстані" +msgstr "" +"Необхідно вказати одиницю виміру при установці відстані бездротового каналу " +"зв'язку" #: wireless/models.py:242 wireless/models.py:248 #, python-brace-format diff --git a/netbox/translations/zh/LC_MESSAGES/django.mo b/netbox/translations/zh/LC_MESSAGES/django.mo index 7affc8f55..c06f982fd 100644 Binary files a/netbox/translations/zh/LC_MESSAGES/django.mo and b/netbox/translations/zh/LC_MESSAGES/django.mo differ diff --git a/netbox/translations/zh/LC_MESSAGES/django.po b/netbox/translations/zh/LC_MESSAGES/django.po index 6e23f1aa9..d6e8190a1 100644 --- a/netbox/translations/zh/LC_MESSAGES/django.po +++ b/netbox/translations/zh/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-28 19:20+0000\n" +"POT-Creation-Date: 2024-11-21 15:50+0000\n" "PO-Revision-Date: 2023-10-30 17:48+0000\n" "Last-Translator: Jeremy Stretch, 2024\n" "Language-Team: Chinese (https://app.transifex.com/netbox-community/teams/178115/zh/)\n" @@ -92,8 +92,8 @@ msgid "Your password has been changed successfully." msgstr "您的密码已成功更改。" #: circuits/choices.py:21 dcim/choices.py:20 dcim/choices.py:102 -#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1530 -#: dcim/choices.py:1606 dcim/choices.py:1656 virtualization/choices.py:20 +#: dcim/choices.py:185 dcim/choices.py:237 dcim/choices.py:1532 +#: dcim/choices.py:1608 dcim/choices.py:1658 virtualization/choices.py:20 #: virtualization/choices.py:45 vpn/choices.py:18 msgid "Planned" msgstr "已规划" @@ -104,7 +104,7 @@ msgstr "置备" #: circuits/choices.py:23 core/tables/tasks.py:22 dcim/choices.py:22 #: dcim/choices.py:103 dcim/choices.py:184 dcim/choices.py:236 -#: dcim/choices.py:1605 dcim/choices.py:1655 extras/tables/tables.py:495 +#: dcim/choices.py:1607 dcim/choices.py:1657 extras/tables/tables.py:495 #: ipam/choices.py:31 ipam/choices.py:49 ipam/choices.py:69 #: ipam/choices.py:154 templates/extras/configcontext.html:25 #: templates/users/user.html:37 users/forms/bulk_edit.py:38 @@ -114,7 +114,7 @@ msgid "Active" msgstr "在线" #: circuits/choices.py:24 dcim/choices.py:183 dcim/choices.py:235 -#: dcim/choices.py:1604 dcim/choices.py:1657 virtualization/choices.py:24 +#: dcim/choices.py:1606 dcim/choices.py:1659 virtualization/choices.py:24 #: virtualization/choices.py:43 msgid "Offline" msgstr "离线" @@ -127,7 +127,7 @@ msgstr "预留" msgid "Decommissioned" msgstr "退役" -#: circuits/choices.py:90 dcim/choices.py:1617 tenancy/choices.py:17 +#: circuits/choices.py:90 dcim/choices.py:1619 tenancy/choices.py:17 msgid "Primary" msgstr "主要联系人" @@ -186,8 +186,8 @@ msgstr "站点组(缩写)" #: circuits/forms/filtersets.py:51 circuits/forms/filtersets.py:171 #: circuits/forms/filtersets.py:209 circuits/forms/model_forms.py:138 #: circuits/forms/model_forms.py:154 circuits/tables/circuits.py:113 -#: dcim/forms/bulk_edit.py:168 dcim/forms/bulk_edit.py:329 -#: dcim/forms/bulk_edit.py:677 dcim/forms/bulk_edit.py:873 +#: dcim/forms/bulk_edit.py:169 dcim/forms/bulk_edit.py:330 +#: dcim/forms/bulk_edit.py:678 dcim/forms/bulk_edit.py:883 #: dcim/forms/bulk_import.py:131 dcim/forms/bulk_import.py:230 #: dcim/forms/bulk_import.py:309 dcim/forms/bulk_import.py:540 #: dcim/forms/bulk_import.py:1311 dcim/forms/bulk_import.py:1339 @@ -352,7 +352,7 @@ msgstr "电路组(slug)" #: circuits/forms/bulk_edit.py:30 circuits/forms/filtersets.py:56 #: circuits/forms/model_forms.py:29 circuits/tables/providers.py:33 -#: dcim/forms/bulk_edit.py:128 dcim/forms/filtersets.py:195 +#: dcim/forms/bulk_edit.py:129 dcim/forms/filtersets.py:195 #: dcim/forms/model_forms.py:123 dcim/tables/sites.py:94 #: ipam/models/asns.py:126 ipam/tables/asn.py:27 ipam/views.py:213 #: netbox/navigation/menu.py:172 netbox/navigation/menu.py:175 @@ -364,21 +364,21 @@ msgstr "自治系统编号/AS编号" #: circuits/forms/bulk_edit.py:83 circuits/forms/bulk_edit.py:104 #: circuits/forms/bulk_edit.py:164 circuits/forms/bulk_edit.py:183 #: circuits/forms/bulk_edit.py:228 core/forms/bulk_edit.py:28 -#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:73 -#: dcim/forms/bulk_edit.py:92 dcim/forms/bulk_edit.py:151 -#: dcim/forms/bulk_edit.py:192 dcim/forms/bulk_edit.py:210 -#: dcim/forms/bulk_edit.py:288 dcim/forms/bulk_edit.py:432 -#: dcim/forms/bulk_edit.py:466 dcim/forms/bulk_edit.py:481 -#: dcim/forms/bulk_edit.py:540 dcim/forms/bulk_edit.py:584 -#: dcim/forms/bulk_edit.py:618 dcim/forms/bulk_edit.py:642 -#: dcim/forms/bulk_edit.py:715 dcim/forms/bulk_edit.py:767 -#: dcim/forms/bulk_edit.py:819 dcim/forms/bulk_edit.py:842 -#: dcim/forms/bulk_edit.py:890 dcim/forms/bulk_edit.py:960 -#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1048 -#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_edit.py:1132 -#: dcim/forms/bulk_edit.py:1177 dcim/forms/bulk_edit.py:1204 -#: dcim/forms/bulk_edit.py:1222 dcim/forms/bulk_edit.py:1240 -#: dcim/forms/bulk_edit.py:1258 dcim/forms/bulk_edit.py:1682 +#: dcim/forms/bulk_create.py:35 dcim/forms/bulk_edit.py:74 +#: dcim/forms/bulk_edit.py:93 dcim/forms/bulk_edit.py:152 +#: dcim/forms/bulk_edit.py:193 dcim/forms/bulk_edit.py:211 +#: dcim/forms/bulk_edit.py:289 dcim/forms/bulk_edit.py:433 +#: dcim/forms/bulk_edit.py:467 dcim/forms/bulk_edit.py:482 +#: dcim/forms/bulk_edit.py:541 dcim/forms/bulk_edit.py:585 +#: dcim/forms/bulk_edit.py:619 dcim/forms/bulk_edit.py:643 +#: dcim/forms/bulk_edit.py:716 dcim/forms/bulk_edit.py:777 +#: dcim/forms/bulk_edit.py:829 dcim/forms/bulk_edit.py:852 +#: dcim/forms/bulk_edit.py:900 dcim/forms/bulk_edit.py:970 +#: dcim/forms/bulk_edit.py:1023 dcim/forms/bulk_edit.py:1058 +#: dcim/forms/bulk_edit.py:1098 dcim/forms/bulk_edit.py:1142 +#: dcim/forms/bulk_edit.py:1187 dcim/forms/bulk_edit.py:1214 +#: dcim/forms/bulk_edit.py:1232 dcim/forms/bulk_edit.py:1250 +#: dcim/forms/bulk_edit.py:1268 dcim/forms/bulk_edit.py:1720 #: extras/forms/bulk_edit.py:39 extras/forms/bulk_edit.py:149 #: extras/forms/bulk_edit.py:178 extras/forms/bulk_edit.py:208 #: extras/forms/bulk_edit.py:256 extras/forms/bulk_edit.py:274 @@ -419,7 +419,7 @@ msgstr "自治系统编号/AS编号" #: templates/extras/dashboard/widget_add.html:14 #: templates/extras/eventrule.html:21 templates/extras/exporttemplate.html:19 #: templates/extras/notificationgroup.html:20 -#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:45 +#: templates/extras/savedfilter.html:17 templates/extras/script_list.html:46 #: templates/extras/tag.html:20 templates/extras/webhook.html:17 #: templates/generic/bulk_import.html:120 templates/ipam/aggregate.html:43 #: templates/ipam/asn.html:42 templates/ipam/asnrange.html:38 @@ -486,9 +486,9 @@ msgid "Service ID" msgstr "服务ID" #: circuits/forms/bulk_edit.py:100 circuits/forms/filtersets.py:107 -#: dcim/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:604 -#: dcim/forms/bulk_edit.py:804 dcim/forms/bulk_edit.py:1173 -#: dcim/forms/bulk_edit.py:1200 dcim/forms/bulk_edit.py:1678 +#: dcim/forms/bulk_edit.py:207 dcim/forms/bulk_edit.py:605 +#: dcim/forms/bulk_edit.py:814 dcim/forms/bulk_edit.py:1183 +#: dcim/forms/bulk_edit.py:1210 dcim/forms/bulk_edit.py:1716 #: dcim/forms/filtersets.py:1064 dcim/forms/filtersets.py:1455 #: dcim/forms/filtersets.py:1479 dcim/tables/devices.py:704 #: dcim/tables/devices.py:761 dcim/tables/devices.py:1003 @@ -505,11 +505,11 @@ msgstr "颜色" #: circuits/forms/bulk_edit.py:118 circuits/forms/bulk_import.py:87 #: circuits/forms/filtersets.py:126 core/forms/bulk_edit.py:18 #: core/forms/filtersets.py:33 core/tables/change_logging.py:32 -#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:782 -#: dcim/forms/bulk_edit.py:921 dcim/forms/bulk_edit.py:989 -#: dcim/forms/bulk_edit.py:1008 dcim/forms/bulk_edit.py:1031 -#: dcim/forms/bulk_edit.py:1073 dcim/forms/bulk_edit.py:1117 -#: dcim/forms/bulk_edit.py:1168 dcim/forms/bulk_edit.py:1195 +#: core/tables/data.py:20 core/tables/jobs.py:18 dcim/forms/bulk_edit.py:792 +#: dcim/forms/bulk_edit.py:931 dcim/forms/bulk_edit.py:999 +#: dcim/forms/bulk_edit.py:1018 dcim/forms/bulk_edit.py:1041 +#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_edit.py:1127 +#: dcim/forms/bulk_edit.py:1178 dcim/forms/bulk_edit.py:1205 #: dcim/forms/bulk_import.py:188 dcim/forms/bulk_import.py:260 #: dcim/forms/bulk_import.py:708 dcim/forms/bulk_import.py:734 #: dcim/forms/bulk_import.py:760 dcim/forms/bulk_import.py:780 @@ -554,11 +554,11 @@ msgstr "运营商账户" #: circuits/forms/bulk_edit.py:136 circuits/forms/bulk_import.py:93 #: circuits/forms/filtersets.py:150 core/forms/filtersets.py:38 #: core/forms/filtersets.py:79 core/tables/data.py:23 core/tables/jobs.py:26 -#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:106 -#: dcim/forms/bulk_edit.py:181 dcim/forms/bulk_edit.py:351 -#: dcim/forms/bulk_edit.py:700 dcim/forms/bulk_edit.py:756 -#: dcim/forms/bulk_edit.py:788 dcim/forms/bulk_edit.py:915 -#: dcim/forms/bulk_edit.py:1701 dcim/forms/bulk_import.py:88 +#: core/tables/tasks.py:88 dcim/forms/bulk_edit.py:107 +#: dcim/forms/bulk_edit.py:182 dcim/forms/bulk_edit.py:352 +#: dcim/forms/bulk_edit.py:701 dcim/forms/bulk_edit.py:766 +#: dcim/forms/bulk_edit.py:798 dcim/forms/bulk_edit.py:925 +#: dcim/forms/bulk_edit.py:1739 dcim/forms/bulk_import.py:88 #: dcim/forms/bulk_import.py:147 dcim/forms/bulk_import.py:248 #: dcim/forms/bulk_import.py:505 dcim/forms/bulk_import.py:659 #: dcim/forms/bulk_import.py:1207 dcim/forms/bulk_import.py:1371 @@ -585,7 +585,7 @@ msgstr "运营商账户" #: templates/dcim/device.html:178 templates/dcim/location.html:45 #: templates/dcim/module.html:69 templates/dcim/powerfeed.html:36 #: templates/dcim/rack.html:41 templates/dcim/site.html:43 -#: templates/extras/script_list.html:47 templates/ipam/ipaddress.html:37 +#: templates/extras/script_list.html:48 templates/ipam/ipaddress.html:37 #: templates/ipam/iprange.html:54 templates/ipam/prefix.html:73 #: templates/ipam/vlan.html:48 templates/virtualization/cluster.html:21 #: templates/virtualization/virtualmachine.html:19 @@ -610,10 +610,10 @@ msgstr "状态" #: circuits/forms/bulk_edit.py:142 circuits/forms/bulk_edit.py:233 #: circuits/forms/bulk_import.py:98 circuits/forms/bulk_import.py:158 #: circuits/forms/filtersets.py:119 circuits/forms/filtersets.py:241 -#: dcim/forms/bulk_edit.py:122 dcim/forms/bulk_edit.py:187 -#: dcim/forms/bulk_edit.py:346 dcim/forms/bulk_edit.py:461 -#: dcim/forms/bulk_edit.py:690 dcim/forms/bulk_edit.py:794 -#: dcim/forms/bulk_edit.py:1706 dcim/forms/bulk_import.py:107 +#: dcim/forms/bulk_edit.py:123 dcim/forms/bulk_edit.py:188 +#: dcim/forms/bulk_edit.py:347 dcim/forms/bulk_edit.py:462 +#: dcim/forms/bulk_edit.py:691 dcim/forms/bulk_edit.py:804 +#: dcim/forms/bulk_edit.py:1744 dcim/forms/bulk_import.py:107 #: dcim/forms/bulk_import.py:152 dcim/forms/bulk_import.py:241 #: dcim/forms/bulk_import.py:334 dcim/forms/bulk_import.py:479 #: dcim/forms/bulk_import.py:1219 dcim/forms/bulk_import.py:1428 @@ -717,11 +717,11 @@ msgstr "端口速度 (Kbps)" msgid "Upstream speed (Kbps)" msgstr "上行速度 (Kbps)" -#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:951 -#: dcim/forms/bulk_edit.py:1315 dcim/forms/bulk_edit.py:1332 -#: dcim/forms/bulk_edit.py:1349 dcim/forms/bulk_edit.py:1367 -#: dcim/forms/bulk_edit.py:1455 dcim/forms/bulk_edit.py:1594 -#: dcim/forms/bulk_edit.py:1611 +#: circuits/forms/bulk_edit.py:206 dcim/forms/bulk_edit.py:961 +#: dcim/forms/bulk_edit.py:1325 dcim/forms/bulk_edit.py:1342 +#: dcim/forms/bulk_edit.py:1359 dcim/forms/bulk_edit.py:1377 +#: dcim/forms/bulk_edit.py:1472 dcim/forms/bulk_edit.py:1632 +#: dcim/forms/bulk_edit.py:1649 msgid "Mark connected" msgstr "标记已连接" @@ -799,9 +799,9 @@ msgid "Provider network" msgstr "运营商网络" #: circuits/forms/filtersets.py:30 circuits/forms/filtersets.py:118 -#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:338 -#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:682 -#: dcim/forms/bulk_edit.py:729 dcim/forms/bulk_edit.py:882 +#: circuits/forms/filtersets.py:200 dcim/forms/bulk_edit.py:339 +#: dcim/forms/bulk_edit.py:442 dcim/forms/bulk_edit.py:683 +#: dcim/forms/bulk_edit.py:738 dcim/forms/bulk_edit.py:892 #: dcim/forms/bulk_import.py:235 dcim/forms/bulk_import.py:315 #: dcim/forms/bulk_import.py:546 dcim/forms/bulk_import.py:1317 #: dcim/forms/bulk_import.py:1351 dcim/forms/filtersets.py:95 @@ -848,8 +848,8 @@ msgid "Contacts" msgstr "联系" #: circuits/forms/filtersets.py:37 circuits/forms/filtersets.py:157 -#: dcim/forms/bulk_edit.py:112 dcim/forms/bulk_edit.py:313 -#: dcim/forms/bulk_edit.py:857 dcim/forms/bulk_import.py:93 +#: dcim/forms/bulk_edit.py:113 dcim/forms/bulk_edit.py:314 +#: dcim/forms/bulk_edit.py:867 dcim/forms/bulk_import.py:93 #: dcim/forms/filtersets.py:73 dcim/forms/filtersets.py:185 #: dcim/forms/filtersets.py:211 dcim/forms/filtersets.py:334 #: dcim/forms/filtersets.py:425 dcim/forms/filtersets.py:739 @@ -872,7 +872,7 @@ msgid "Region" msgstr "地区" #: circuits/forms/filtersets.py:42 circuits/forms/filtersets.py:162 -#: dcim/forms/bulk_edit.py:321 dcim/forms/bulk_edit.py:865 +#: dcim/forms/bulk_edit.py:322 dcim/forms/bulk_edit.py:875 #: dcim/forms/filtersets.py:78 dcim/forms/filtersets.py:190 #: dcim/forms/filtersets.py:216 dcim/forms/filtersets.py:347 #: dcim/forms/filtersets.py:430 dcim/forms/filtersets.py:744 @@ -890,7 +890,7 @@ msgstr "站点组" #: circuits/forms/filtersets.py:65 circuits/forms/filtersets.py:83 #: circuits/forms/filtersets.py:102 circuits/forms/filtersets.py:117 #: core/forms/filtersets.py:67 core/forms/filtersets.py:135 -#: dcim/forms/bulk_edit.py:828 dcim/forms/filtersets.py:172 +#: dcim/forms/bulk_edit.py:838 dcim/forms/filtersets.py:172 #: dcim/forms/filtersets.py:204 dcim/forms/filtersets.py:915 #: dcim/forms/filtersets.py:1007 dcim/forms/filtersets.py:1131 #: dcim/forms/filtersets.py:1239 dcim/forms/filtersets.py:1263 @@ -925,16 +925,17 @@ msgstr "账户" msgid "Term Side" msgstr "线路终端侧" -#: circuits/forms/filtersets.py:250 extras/forms/model_forms.py:582 -#: ipam/forms/filtersets.py:142 ipam/forms/filtersets.py:546 -#: ipam/forms/model_forms.py:323 templates/extras/configcontext.html:60 -#: templates/ipam/ipaddress.html:59 templates/ipam/vlan_edit.html:30 -#: tenancy/forms/filtersets.py:87 users/forms/model_forms.py:314 +#: circuits/forms/filtersets.py:250 dcim/forms/bulk_edit.py:1552 +#: extras/forms/model_forms.py:582 ipam/forms/filtersets.py:142 +#: ipam/forms/filtersets.py:546 ipam/forms/model_forms.py:323 +#: templates/extras/configcontext.html:60 templates/ipam/ipaddress.html:59 +#: templates/ipam/vlan_edit.html:30 tenancy/forms/filtersets.py:87 +#: users/forms/model_forms.py:314 msgid "Assignment" msgstr "分配" #: circuits/forms/filtersets.py:265 circuits/forms/model_forms.py:195 -#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:117 +#: circuits/tables/circuits.py:155 dcim/forms/bulk_edit.py:118 #: dcim/forms/bulk_import.py:100 dcim/forms/model_forms.py:117 #: dcim/tables/sites.py:89 extras/forms/filtersets.py:480 #: ipam/filtersets.py:999 ipam/forms/bulk_edit.py:493 @@ -1000,7 +1001,7 @@ msgstr "唯一线路 ID" #: dcim/models/devices.py:1173 dcim/models/devices.py:1399 #: dcim/models/power.py:96 dcim/models/racks.py:297 dcim/models/sites.py:154 #: dcim/models/sites.py:266 ipam/models/ip.py:253 ipam/models/ip.py:522 -#: ipam/models/ip.py:730 ipam/models/vlans.py:195 +#: ipam/models/ip.py:730 ipam/models/vlans.py:211 #: virtualization/models/clusters.py:74 #: virtualization/models/virtualmachines.py:84 vpn/models/tunnels.py:40 #: wireless/models.py:95 wireless/models.py:159 @@ -1135,7 +1136,7 @@ msgstr "线路终结不能同时连接到站点和运营商网络。" #: extras/models/notifications.py:126 extras/models/scripts.py:30 #: extras/models/staging.py:26 ipam/models/asns.py:18 ipam/models/fhrp.py:25 #: ipam/models/services.py:52 ipam/models/services.py:88 -#: ipam/models/vlans.py:36 ipam/models/vlans.py:184 ipam/models/vrfs.py:22 +#: ipam/models/vlans.py:36 ipam/models/vlans.py:200 ipam/models/vrfs.py:22 #: ipam/models/vrfs.py:79 netbox/models/__init__.py:137 #: netbox/models/__init__.py:181 tenancy/models/contacts.py:64 #: tenancy/models/tenants.py:20 tenancy/models/tenants.py:45 @@ -1246,7 +1247,7 @@ msgstr "运营商网络" #: templates/extras/customfield.html:13 templates/extras/customlink.html:13 #: templates/extras/eventrule.html:13 templates/extras/exporttemplate.html:15 #: templates/extras/notificationgroup.html:14 -#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:44 +#: templates/extras/savedfilter.html:13 templates/extras/script_list.html:45 #: templates/extras/tag.html:14 templates/extras/webhook.html:13 #: templates/ipam/asnrange.html:15 templates/ipam/fhrpgroup.html:30 #: templates/ipam/rir.html:22 templates/ipam/role.html:22 @@ -1383,7 +1384,7 @@ msgstr "完成" #: core/choices.py:22 core/choices.py:59 core/constants.py:20 #: core/tables/tasks.py:34 dcim/choices.py:187 dcim/choices.py:239 -#: dcim/choices.py:1607 virtualization/choices.py:47 +#: dcim/choices.py:1609 virtualization/choices.py:47 msgid "Failed" msgstr "故障" @@ -1530,8 +1531,8 @@ msgid "User name" msgstr "用户名" #: core/forms/bulk_edit.py:25 core/forms/filtersets.py:43 -#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1122 -#: dcim/forms/bulk_edit.py:1400 dcim/forms/filtersets.py:1370 +#: core/tables/data.py:26 dcim/forms/bulk_edit.py:1132 +#: dcim/forms/bulk_edit.py:1410 dcim/forms/filtersets.py:1370 #: dcim/tables/devices.py:553 dcim/tables/devicetypes.py:224 #: extras/forms/bulk_edit.py:123 extras/forms/bulk_edit.py:187 #: extras/forms/bulk_edit.py:246 extras/forms/filtersets.py:142 @@ -1631,7 +1632,7 @@ msgid "Completed before" msgstr "完成后" #: core/forms/filtersets.py:126 core/forms/filtersets.py:155 -#: dcim/forms/bulk_edit.py:456 dcim/forms/filtersets.py:418 +#: dcim/forms/bulk_edit.py:457 dcim/forms/filtersets.py:418 #: dcim/forms/filtersets.py:462 dcim/forms/model_forms.py:316 #: extras/forms/filtersets.py:456 extras/forms/filtersets.py:475 #: extras/tables/tables.py:302 extras/tables/tables.py:342 @@ -1691,9 +1692,9 @@ msgstr "必须上传文件或选择数据文件进行同步" msgid "Rack Elevations" msgstr "机柜立面图" -#: core/forms/model_forms.py:157 dcim/choices.py:1518 -#: dcim/forms/bulk_edit.py:969 dcim/forms/bulk_edit.py:1357 -#: dcim/forms/bulk_edit.py:1375 dcim/tables/racks.py:158 +#: core/forms/model_forms.py:157 dcim/choices.py:1520 +#: dcim/forms/bulk_edit.py:979 dcim/forms/bulk_edit.py:1367 +#: dcim/forms/bulk_edit.py:1385 dcim/tables/racks.py:158 #: netbox/navigation/menu.py:291 netbox/navigation/menu.py:295 msgid "Power" msgstr "电源" @@ -2219,11 +2220,11 @@ msgstr "工作 {id} 已停止。" msgid "Failed to stop job {id}" msgstr "无法停止作业 {id}" -#: core/views.py:678 +#: core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "无法加载插件目录" -#: core/views.py:712 +#: core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "插件 {name} 未找到" @@ -2241,7 +2242,7 @@ msgid "Staging" msgstr "暂存" #: dcim/choices.py:23 dcim/choices.py:189 dcim/choices.py:240 -#: dcim/choices.py:1531 virtualization/choices.py:23 +#: dcim/choices.py:1533 virtualization/choices.py:23 #: virtualization/choices.py:48 msgid "Decommissioning" msgstr "报废" @@ -2301,7 +2302,7 @@ msgstr "已弃用" msgid "Millimeters" msgstr "毫米" -#: dcim/choices.py:115 dcim/choices.py:1553 +#: dcim/choices.py:115 dcim/choices.py:1555 msgid "Inches" msgstr "英寸" @@ -2313,8 +2314,8 @@ msgstr "从前向后" msgid "Rear to front" msgstr "从后向前" -#: dcim/choices.py:151 dcim/forms/bulk_edit.py:68 dcim/forms/bulk_edit.py:87 -#: dcim/forms/bulk_edit.py:173 dcim/forms/bulk_edit.py:1405 +#: dcim/choices.py:151 dcim/forms/bulk_edit.py:69 dcim/forms/bulk_edit.py:88 +#: dcim/forms/bulk_edit.py:174 dcim/forms/bulk_edit.py:1415 #: dcim/forms/bulk_import.py:60 dcim/forms/bulk_import.py:74 #: dcim/forms/bulk_import.py:137 dcim/forms/bulk_import.py:566 #: dcim/forms/bulk_import.py:833 dcim/forms/bulk_import.py:1088 @@ -2388,7 +2389,7 @@ msgstr "自下而上" msgid "Top to bottom" msgstr "从上到下" -#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1303 +#: dcim/choices.py:215 dcim/choices.py:259 dcim/choices.py:1305 msgid "Passive" msgstr "被动" @@ -2416,8 +2417,8 @@ msgstr "国际通用标准/ITA" msgid "Proprietary" msgstr "专用规格" -#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1219 -#: dcim/choices.py:1221 dcim/choices.py:1447 dcim/choices.py:1449 +#: dcim/choices.py:581 dcim/choices.py:824 dcim/choices.py:1221 +#: dcim/choices.py:1223 dcim/choices.py:1449 dcim/choices.py:1451 #: netbox/navigation/menu.py:200 msgid "Other" msgstr "其他" @@ -2430,22 +2431,22 @@ msgstr "ITA/国际通用标准" msgid "Physical" msgstr "物理" -#: dcim/choices.py:855 dcim/choices.py:1023 +#: dcim/choices.py:855 dcim/choices.py:1024 msgid "Virtual" msgstr "虚拟" -#: dcim/choices.py:856 dcim/choices.py:1097 dcim/forms/bulk_edit.py:1515 +#: dcim/choices.py:856 dcim/choices.py:1099 dcim/forms/bulk_edit.py:1558 #: dcim/forms/filtersets.py:1330 dcim/forms/model_forms.py:988 #: dcim/forms/model_forms.py:1397 netbox/navigation/menu.py:140 #: netbox/navigation/menu.py:144 templates/dcim/interface.html:210 msgid "Wireless" msgstr "无线" -#: dcim/choices.py:1021 +#: dcim/choices.py:1022 msgid "Virtual interfaces" msgstr "虚拟接口" -#: dcim/choices.py:1024 dcim/forms/bulk_edit.py:1410 +#: dcim/choices.py:1025 dcim/forms/bulk_edit.py:1423 #: dcim/forms/bulk_import.py:840 dcim/forms/model_forms.py:974 #: dcim/tables/devices.py:660 templates/dcim/interface.html:106 #: templates/virtualization/vminterface.html:43 @@ -2455,155 +2456,155 @@ msgstr "虚拟接口" msgid "Bridge" msgstr "桥接" -#: dcim/choices.py:1025 +#: dcim/choices.py:1026 msgid "Link Aggregation Group (LAG)" msgstr "链路聚合组(LAG)" -#: dcim/choices.py:1029 +#: dcim/choices.py:1030 msgid "Ethernet (fixed)" msgstr "以太网(固定类型)" -#: dcim/choices.py:1044 +#: dcim/choices.py:1046 msgid "Ethernet (modular)" msgstr "以太网(模块)" -#: dcim/choices.py:1081 +#: dcim/choices.py:1083 msgid "Ethernet (backplane)" msgstr "以太网(背板)" -#: dcim/choices.py:1113 +#: dcim/choices.py:1115 msgid "Cellular" msgstr "蜂窝网络" -#: dcim/choices.py:1165 dcim/forms/filtersets.py:383 +#: dcim/choices.py:1167 dcim/forms/filtersets.py:383 #: dcim/forms/filtersets.py:809 dcim/forms/filtersets.py:963 #: dcim/forms/filtersets.py:1542 templates/dcim/inventoryitem.html:52 #: templates/dcim/virtualchassis_edit.html:54 msgid "Serial" msgstr "串口" -#: dcim/choices.py:1180 +#: dcim/choices.py:1182 msgid "Coaxial" msgstr "同轴电缆接口" -#: dcim/choices.py:1200 +#: dcim/choices.py:1202 msgid "Stacking" msgstr "堆叠" -#: dcim/choices.py:1250 +#: dcim/choices.py:1252 msgid "Half" msgstr "半双工" -#: dcim/choices.py:1251 +#: dcim/choices.py:1253 msgid "Full" msgstr "全双工" -#: dcim/choices.py:1252 netbox/preferences.py:31 wireless/choices.py:480 +#: dcim/choices.py:1254 netbox/preferences.py:31 wireless/choices.py:480 msgid "Auto" msgstr "自动" -#: dcim/choices.py:1263 +#: dcim/choices.py:1265 msgid "Access" msgstr "接入" -#: dcim/choices.py:1264 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 +#: dcim/choices.py:1266 ipam/tables/vlans.py:172 ipam/tables/vlans.py:217 #: templates/dcim/inc/interface_vlans_table.html:7 msgid "Tagged" msgstr "Trunk口" -#: dcim/choices.py:1265 +#: dcim/choices.py:1267 msgid "Tagged (All)" msgstr "Trunk口(允许所有VLAN)" -#: dcim/choices.py:1294 +#: dcim/choices.py:1296 msgid "IEEE Standard" msgstr "IEEE标准" -#: dcim/choices.py:1305 +#: dcim/choices.py:1307 msgid "Passive 24V (2-pair)" msgstr "24V(2对供电)" -#: dcim/choices.py:1306 +#: dcim/choices.py:1308 msgid "Passive 24V (4-pair)" msgstr "24V(4对供电)" -#: dcim/choices.py:1307 +#: dcim/choices.py:1309 msgid "Passive 48V (2-pair)" msgstr "48V(2对供电)" -#: dcim/choices.py:1308 +#: dcim/choices.py:1310 msgid "Passive 48V (4-pair)" msgstr "48V(4对供电)" -#: dcim/choices.py:1378 dcim/choices.py:1488 +#: dcim/choices.py:1380 dcim/choices.py:1490 msgid "Copper" msgstr "铜缆" -#: dcim/choices.py:1401 +#: dcim/choices.py:1403 msgid "Fiber Optic" msgstr "光纤" -#: dcim/choices.py:1434 dcim/choices.py:1517 +#: dcim/choices.py:1436 dcim/choices.py:1519 msgid "USB" msgstr "USB" -#: dcim/choices.py:1504 +#: dcim/choices.py:1506 msgid "Fiber" msgstr "光纤" -#: dcim/choices.py:1529 dcim/forms/filtersets.py:1227 +#: dcim/choices.py:1531 dcim/forms/filtersets.py:1227 msgid "Connected" msgstr "已连接" -#: dcim/choices.py:1548 wireless/choices.py:497 +#: dcim/choices.py:1550 wireless/choices.py:497 msgid "Kilometers" msgstr "公里" -#: dcim/choices.py:1549 templates/dcim/cable_trace.html:65 +#: dcim/choices.py:1551 templates/dcim/cable_trace.html:65 #: wireless/choices.py:498 msgid "Meters" msgstr "米" -#: dcim/choices.py:1550 +#: dcim/choices.py:1552 msgid "Centimeters" msgstr "厘米" -#: dcim/choices.py:1551 wireless/choices.py:499 +#: dcim/choices.py:1553 wireless/choices.py:499 msgid "Miles" msgstr "英里" -#: dcim/choices.py:1552 templates/dcim/cable_trace.html:66 +#: dcim/choices.py:1554 templates/dcim/cable_trace.html:66 #: wireless/choices.py:500 msgid "Feet" msgstr "英尺" -#: dcim/choices.py:1568 templates/dcim/device.html:327 +#: dcim/choices.py:1570 templates/dcim/device.html:327 #: templates/dcim/rack.html:107 msgid "Kilograms" msgstr "千克" -#: dcim/choices.py:1569 +#: dcim/choices.py:1571 msgid "Grams" msgstr "克" -#: dcim/choices.py:1570 templates/dcim/device.html:328 +#: dcim/choices.py:1572 templates/dcim/device.html:328 #: templates/dcim/rack.html:108 msgid "Pounds" msgstr "磅" -#: dcim/choices.py:1571 +#: dcim/choices.py:1573 msgid "Ounces" msgstr "盎司" -#: dcim/choices.py:1618 +#: dcim/choices.py:1620 msgid "Redundant" msgstr "冗余" -#: dcim/choices.py:1639 +#: dcim/choices.py:1641 msgid "Single phase" msgstr "单相电" -#: dcim/choices.py:1640 +#: dcim/choices.py:1642 msgid "Three-phase" msgstr "三相" @@ -2836,7 +2837,7 @@ msgstr "集群组(ID)" msgid "Device model (slug)" msgstr "设备模块(缩写)" -#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:516 +#: dcim/filtersets.py:1099 dcim/forms/bulk_edit.py:517 msgid "Is full depth" msgstr "是否全尺寸" @@ -2952,7 +2953,7 @@ msgstr "指定VLAN" msgid "Assigned VID" msgstr "指定VID" -#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1489 +#: dcim/filtersets.py:1613 dcim/forms/bulk_edit.py:1526 #: dcim/forms/bulk_import.py:891 dcim/forms/filtersets.py:1428 #: dcim/forms/model_forms.py:1378 dcim/models/device_components.py:711 #: dcim/tables/devices.py:626 ipam/filtersets.py:316 ipam/filtersets.py:327 @@ -3111,27 +3112,27 @@ msgid "" "created.)" msgstr "支持字母和数字。(必须与正在创建的名称数相匹配)" -#: dcim/forms/bulk_edit.py:132 +#: dcim/forms/bulk_edit.py:133 msgid "Contact name" msgstr "联系人名字" -#: dcim/forms/bulk_edit.py:137 +#: dcim/forms/bulk_edit.py:138 msgid "Contact phone" msgstr "联系人手机" -#: dcim/forms/bulk_edit.py:143 +#: dcim/forms/bulk_edit.py:144 msgid "Contact E-mail" msgstr "联系人电子邮箱" -#: dcim/forms/bulk_edit.py:146 dcim/forms/bulk_import.py:123 +#: dcim/forms/bulk_edit.py:147 dcim/forms/bulk_import.py:123 #: dcim/forms/model_forms.py:128 msgid "Time zone" msgstr "时区" -#: dcim/forms/bulk_edit.py:224 dcim/forms/bulk_edit.py:495 -#: dcim/forms/bulk_edit.py:559 dcim/forms/bulk_edit.py:632 -#: dcim/forms/bulk_edit.py:656 dcim/forms/bulk_edit.py:740 -#: dcim/forms/bulk_edit.py:1267 dcim/forms/bulk_edit.py:1660 +#: dcim/forms/bulk_edit.py:225 dcim/forms/bulk_edit.py:496 +#: dcim/forms/bulk_edit.py:560 dcim/forms/bulk_edit.py:633 +#: dcim/forms/bulk_edit.py:657 dcim/forms/bulk_edit.py:750 +#: dcim/forms/bulk_edit.py:1277 dcim/forms/bulk_edit.py:1698 #: dcim/forms/bulk_import.py:182 dcim/forms/bulk_import.py:371 #: dcim/forms/bulk_import.py:405 dcim/forms/bulk_import.py:450 #: dcim/forms/bulk_import.py:486 dcim/forms/bulk_import.py:1082 @@ -3154,51 +3155,51 @@ msgstr "时区" msgid "Manufacturer" msgstr "厂商" -#: dcim/forms/bulk_edit.py:229 dcim/forms/bulk_edit.py:372 +#: dcim/forms/bulk_edit.py:230 dcim/forms/bulk_edit.py:373 #: dcim/forms/bulk_import.py:191 dcim/forms/bulk_import.py:263 #: dcim/forms/filtersets.py:255 #: templates/dcim/inc/panels/racktype_dimensions.html:6 msgid "Form factor" msgstr "外形规格" -#: dcim/forms/bulk_edit.py:234 dcim/forms/bulk_edit.py:377 +#: dcim/forms/bulk_edit.py:235 dcim/forms/bulk_edit.py:378 #: dcim/forms/bulk_import.py:199 dcim/forms/bulk_import.py:266 #: dcim/forms/filtersets.py:260 #: templates/dcim/inc/panels/racktype_dimensions.html:10 msgid "Width" msgstr "宽度" -#: dcim/forms/bulk_edit.py:240 dcim/forms/bulk_edit.py:383 +#: dcim/forms/bulk_edit.py:241 dcim/forms/bulk_edit.py:384 #: templates/dcim/devicetype.html:37 msgid "Height (U)" msgstr "高度(U)" -#: dcim/forms/bulk_edit.py:249 dcim/forms/bulk_edit.py:388 +#: dcim/forms/bulk_edit.py:250 dcim/forms/bulk_edit.py:389 #: dcim/forms/filtersets.py:274 msgid "Descending units" msgstr "U位显示降序" -#: dcim/forms/bulk_edit.py:252 dcim/forms/bulk_edit.py:391 +#: dcim/forms/bulk_edit.py:253 dcim/forms/bulk_edit.py:392 msgid "Outer width" msgstr "外部宽度" -#: dcim/forms/bulk_edit.py:257 dcim/forms/bulk_edit.py:396 +#: dcim/forms/bulk_edit.py:258 dcim/forms/bulk_edit.py:397 msgid "Outer depth" msgstr "外部深度" -#: dcim/forms/bulk_edit.py:262 dcim/forms/bulk_edit.py:401 +#: dcim/forms/bulk_edit.py:263 dcim/forms/bulk_edit.py:402 #: dcim/forms/bulk_import.py:204 dcim/forms/bulk_import.py:271 msgid "Outer unit" msgstr "外部单元" -#: dcim/forms/bulk_edit.py:267 dcim/forms/bulk_edit.py:406 +#: dcim/forms/bulk_edit.py:268 dcim/forms/bulk_edit.py:407 msgid "Mounting depth" msgstr "安装深度" -#: dcim/forms/bulk_edit.py:272 dcim/forms/bulk_edit.py:299 -#: dcim/forms/bulk_edit.py:416 dcim/forms/bulk_edit.py:446 -#: dcim/forms/bulk_edit.py:529 dcim/forms/bulk_edit.py:552 -#: dcim/forms/bulk_edit.py:573 dcim/forms/bulk_edit.py:595 +#: dcim/forms/bulk_edit.py:273 dcim/forms/bulk_edit.py:300 +#: dcim/forms/bulk_edit.py:417 dcim/forms/bulk_edit.py:447 +#: dcim/forms/bulk_edit.py:530 dcim/forms/bulk_edit.py:553 +#: dcim/forms/bulk_edit.py:574 dcim/forms/bulk_edit.py:596 #: dcim/forms/bulk_import.py:384 dcim/forms/bulk_import.py:416 #: dcim/forms/filtersets.py:285 dcim/forms/filtersets.py:307 #: dcim/forms/filtersets.py:327 dcim/forms/filtersets.py:401 @@ -3219,13 +3220,13 @@ msgstr "安装深度" msgid "Weight" msgstr "重量" -#: dcim/forms/bulk_edit.py:277 dcim/forms/bulk_edit.py:421 +#: dcim/forms/bulk_edit.py:278 dcim/forms/bulk_edit.py:422 #: dcim/forms/filtersets.py:290 msgid "Max weight" msgstr "最大承重" -#: dcim/forms/bulk_edit.py:282 dcim/forms/bulk_edit.py:426 -#: dcim/forms/bulk_edit.py:534 dcim/forms/bulk_edit.py:578 +#: dcim/forms/bulk_edit.py:283 dcim/forms/bulk_edit.py:427 +#: dcim/forms/bulk_edit.py:535 dcim/forms/bulk_edit.py:579 #: dcim/forms/bulk_import.py:210 dcim/forms/bulk_import.py:283 #: dcim/forms/bulk_import.py:389 dcim/forms/bulk_import.py:421 #: dcim/forms/filtersets.py:295 dcim/forms/filtersets.py:598 @@ -3233,31 +3234,31 @@ msgstr "最大承重" msgid "Weight unit" msgstr "重量单位" -#: dcim/forms/bulk_edit.py:296 dcim/forms/filtersets.py:305 +#: dcim/forms/bulk_edit.py:297 dcim/forms/filtersets.py:305 #: dcim/forms/model_forms.py:217 dcim/forms/model_forms.py:256 #: templates/dcim/rack.html:45 templates/dcim/racktype.html:13 msgid "Rack Type" msgstr "机架类型" -#: dcim/forms/bulk_edit.py:298 dcim/forms/model_forms.py:220 +#: dcim/forms/bulk_edit.py:299 dcim/forms/model_forms.py:220 #: dcim/forms/model_forms.py:297 msgid "Outer Dimensions" msgstr "外部尺寸" -#: dcim/forms/bulk_edit.py:301 dcim/forms/model_forms.py:222 +#: dcim/forms/bulk_edit.py:302 dcim/forms/model_forms.py:222 #: dcim/forms/model_forms.py:299 templates/dcim/device.html:315 #: templates/dcim/inc/panels/racktype_dimensions.html:3 msgid "Dimensions" msgstr "外部尺寸" -#: dcim/forms/bulk_edit.py:303 dcim/forms/filtersets.py:306 +#: dcim/forms/bulk_edit.py:304 dcim/forms/filtersets.py:306 #: dcim/forms/filtersets.py:326 dcim/forms/model_forms.py:224 #: templates/dcim/inc/panels/racktype_numbering.html:3 msgid "Numbering" msgstr "编号" -#: dcim/forms/bulk_edit.py:357 dcim/forms/bulk_edit.py:1262 -#: dcim/forms/bulk_edit.py:1655 dcim/forms/bulk_import.py:253 +#: dcim/forms/bulk_edit.py:358 dcim/forms/bulk_edit.py:1272 +#: dcim/forms/bulk_edit.py:1693 dcim/forms/bulk_import.py:253 #: dcim/forms/bulk_import.py:1076 dcim/forms/filtersets.py:367 #: dcim/forms/filtersets.py:777 dcim/forms/filtersets.py:1534 #: dcim/forms/model_forms.py:251 dcim/forms/model_forms.py:1070 @@ -3297,21 +3298,21 @@ msgstr "编号" msgid "Role" msgstr "角色" -#: dcim/forms/bulk_edit.py:364 dcim/forms/bulk_edit.py:712 -#: dcim/forms/bulk_edit.py:764 templates/dcim/device.html:104 +#: dcim/forms/bulk_edit.py:365 dcim/forms/bulk_edit.py:713 +#: dcim/forms/bulk_edit.py:774 templates/dcim/device.html:104 #: templates/dcim/module.html:77 templates/dcim/modulebay.html:70 #: templates/dcim/rack.html:57 templates/virtualization/virtualmachine.html:35 msgid "Serial Number" msgstr "序列号" -#: dcim/forms/bulk_edit.py:367 dcim/forms/filtersets.py:387 +#: dcim/forms/bulk_edit.py:368 dcim/forms/filtersets.py:387 #: dcim/forms/filtersets.py:813 dcim/forms/filtersets.py:967 #: dcim/forms/filtersets.py:1546 msgid "Asset tag" msgstr "资产标签" -#: dcim/forms/bulk_edit.py:411 dcim/forms/bulk_edit.py:524 -#: dcim/forms/bulk_edit.py:568 dcim/forms/bulk_edit.py:705 +#: dcim/forms/bulk_edit.py:412 dcim/forms/bulk_edit.py:525 +#: dcim/forms/bulk_edit.py:569 dcim/forms/bulk_edit.py:706 #: dcim/forms/bulk_import.py:277 dcim/forms/bulk_import.py:410 #: dcim/forms/bulk_import.py:580 dcim/forms/filtersets.py:280 #: dcim/forms/filtersets.py:511 dcim/forms/filtersets.py:669 @@ -3321,7 +3322,7 @@ msgstr "资产标签" msgid "Airflow" msgstr "气流方向" -#: dcim/forms/bulk_edit.py:440 dcim/forms/bulk_edit.py:910 +#: dcim/forms/bulk_edit.py:441 dcim/forms/bulk_edit.py:920 #: dcim/forms/bulk_import.py:322 dcim/forms/bulk_import.py:325 #: dcim/forms/bulk_import.py:553 dcim/forms/bulk_import.py:1358 #: dcim/forms/bulk_import.py:1362 dcim/forms/filtersets.py:104 @@ -3341,7 +3342,7 @@ msgstr "气流方向" msgid "Rack" msgstr "机柜" -#: dcim/forms/bulk_edit.py:444 dcim/forms/bulk_edit.py:730 +#: dcim/forms/bulk_edit.py:445 dcim/forms/bulk_edit.py:739 #: dcim/forms/filtersets.py:325 dcim/forms/filtersets.py:398 #: dcim/forms/filtersets.py:481 dcim/forms/filtersets.py:608 #: dcim/forms/filtersets.py:721 dcim/forms/filtersets.py:942 @@ -3350,49 +3351,49 @@ msgstr "机柜" msgid "Hardware" msgstr "硬件" -#: dcim/forms/bulk_edit.py:500 dcim/forms/bulk_import.py:377 +#: dcim/forms/bulk_edit.py:501 dcim/forms/bulk_import.py:377 #: dcim/forms/filtersets.py:499 dcim/forms/model_forms.py:353 msgid "Default platform" msgstr "默认系统平台" -#: dcim/forms/bulk_edit.py:505 dcim/forms/bulk_edit.py:564 +#: dcim/forms/bulk_edit.py:506 dcim/forms/bulk_edit.py:565 #: dcim/forms/filtersets.py:502 dcim/forms/filtersets.py:622 msgid "Part number" msgstr "部件编码(PN)" -#: dcim/forms/bulk_edit.py:509 +#: dcim/forms/bulk_edit.py:510 msgid "U height" msgstr "U高度" -#: dcim/forms/bulk_edit.py:521 dcim/tables/devicetypes.py:102 +#: dcim/forms/bulk_edit.py:522 dcim/tables/devicetypes.py:102 msgid "Exclude from utilization" msgstr "从利用率中排除" -#: dcim/forms/bulk_edit.py:550 dcim/forms/model_forms.py:368 +#: dcim/forms/bulk_edit.py:551 dcim/forms/model_forms.py:368 #: dcim/tables/devicetypes.py:77 templates/dcim/device.html:88 #: templates/dcim/devicebay.html:52 templates/dcim/module.html:61 msgid "Device Type" msgstr "设备型号" -#: dcim/forms/bulk_edit.py:592 dcim/forms/model_forms.py:401 +#: dcim/forms/bulk_edit.py:593 dcim/forms/model_forms.py:401 #: dcim/tables/modules.py:17 dcim/tables/modules.py:65 #: templates/dcim/module.html:65 templates/dcim/modulebay.html:66 #: templates/dcim/moduletype.html:22 msgid "Module Type" msgstr "设备配件类型" -#: dcim/forms/bulk_edit.py:596 dcim/forms/model_forms.py:371 +#: dcim/forms/bulk_edit.py:597 dcim/forms/model_forms.py:371 #: dcim/forms/model_forms.py:402 templates/dcim/devicetype.html:11 msgid "Chassis" msgstr "机箱" -#: dcim/forms/bulk_edit.py:610 dcim/models/devices.py:484 +#: dcim/forms/bulk_edit.py:611 dcim/models/devices.py:484 #: dcim/tables/devices.py:67 msgid "VM role" msgstr "VM 角色" -#: dcim/forms/bulk_edit.py:613 dcim/forms/bulk_edit.py:637 -#: dcim/forms/bulk_edit.py:720 dcim/forms/bulk_import.py:434 +#: dcim/forms/bulk_edit.py:614 dcim/forms/bulk_edit.py:638 +#: dcim/forms/bulk_edit.py:721 dcim/forms/bulk_import.py:434 #: dcim/forms/bulk_import.py:438 dcim/forms/bulk_import.py:457 #: dcim/forms/bulk_import.py:461 dcim/forms/bulk_import.py:586 #: dcim/forms/bulk_import.py:590 dcim/forms/filtersets.py:689 @@ -3405,19 +3406,19 @@ msgstr "VM 角色" msgid "Config template" msgstr "配置模版" -#: dcim/forms/bulk_edit.py:661 dcim/forms/bulk_edit.py:1061 +#: dcim/forms/bulk_edit.py:662 dcim/forms/bulk_edit.py:1071 #: dcim/forms/bulk_import.py:492 dcim/forms/filtersets.py:114 #: dcim/forms/model_forms.py:501 dcim/forms/model_forms.py:872 #: dcim/forms/model_forms.py:889 extras/filtersets.py:547 msgid "Device type" msgstr "设备型号" -#: dcim/forms/bulk_edit.py:672 dcim/forms/bulk_import.py:473 +#: dcim/forms/bulk_edit.py:673 dcim/forms/bulk_import.py:473 #: dcim/forms/filtersets.py:119 dcim/forms/model_forms.py:509 msgid "Device role" msgstr "设备角色" -#: dcim/forms/bulk_edit.py:695 dcim/forms/bulk_import.py:498 +#: dcim/forms/bulk_edit.py:696 dcim/forms/bulk_import.py:498 #: dcim/forms/filtersets.py:796 dcim/forms/model_forms.py:451 #: dcim/forms/model_forms.py:513 dcim/tables/devices.py:182 #: extras/filtersets.py:563 templates/dcim/device.html:186 @@ -3431,8 +3432,28 @@ msgstr "设备角色" msgid "Platform" msgstr "平台" -#: dcim/forms/bulk_edit.py:728 dcim/forms/bulk_edit.py:1281 -#: dcim/forms/bulk_edit.py:1650 dcim/forms/bulk_edit.py:1696 +#: dcim/forms/bulk_edit.py:726 dcim/forms/bulk_import.py:517 +#: dcim/forms/filtersets.py:728 dcim/forms/filtersets.py:898 +#: dcim/forms/model_forms.py:522 dcim/tables/devices.py:202 +#: extras/filtersets.py:596 extras/forms/filtersets.py:322 +#: ipam/forms/filtersets.py:415 ipam/forms/filtersets.py:447 +#: templates/dcim/device.html:239 templates/virtualization/cluster.html:10 +#: templates/virtualization/virtualmachine.html:92 +#: templates/virtualization/virtualmachine.html:101 +#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 +#: virtualization/forms/bulk_edit.py:129 +#: virtualization/forms/bulk_import.py:92 +#: virtualization/forms/filtersets.py:99 +#: virtualization/forms/filtersets.py:123 +#: virtualization/forms/filtersets.py:204 +#: virtualization/forms/model_forms.py:79 +#: virtualization/forms/model_forms.py:176 +#: virtualization/tables/virtualmachines.py:67 +msgid "Cluster" +msgstr "集群" + +#: dcim/forms/bulk_edit.py:737 dcim/forms/bulk_edit.py:1291 +#: dcim/forms/bulk_edit.py:1688 dcim/forms/bulk_edit.py:1734 #: dcim/forms/bulk_import.py:641 dcim/forms/bulk_import.py:703 #: dcim/forms/bulk_import.py:729 dcim/forms/bulk_import.py:755 #: dcim/forms/bulk_import.py:775 dcim/forms/bulk_import.py:828 @@ -3489,22 +3510,27 @@ msgstr "平台" msgid "Device" msgstr "设备" -#: dcim/forms/bulk_edit.py:731 templates/extras/dashboard/widget_config.html:7 +#: dcim/forms/bulk_edit.py:740 templates/extras/dashboard/widget_config.html:7 #: virtualization/forms/bulk_edit.py:191 msgid "Configuration" msgstr "配置" -#: dcim/forms/bulk_edit.py:745 dcim/forms/bulk_import.py:653 +#: dcim/forms/bulk_edit.py:741 netbox/navigation/menu.py:243 +#: templates/dcim/device_edit.html:78 +msgid "Virtualization" +msgstr "虚拟化" + +#: dcim/forms/bulk_edit.py:755 dcim/forms/bulk_import.py:653 #: dcim/forms/model_forms.py:647 dcim/forms/model_forms.py:897 msgid "Module type" msgstr "模块类型" -#: dcim/forms/bulk_edit.py:799 dcim/forms/bulk_edit.py:984 -#: dcim/forms/bulk_edit.py:1003 dcim/forms/bulk_edit.py:1026 -#: dcim/forms/bulk_edit.py:1068 dcim/forms/bulk_edit.py:1112 -#: dcim/forms/bulk_edit.py:1163 dcim/forms/bulk_edit.py:1190 -#: dcim/forms/bulk_edit.py:1217 dcim/forms/bulk_edit.py:1235 -#: dcim/forms/bulk_edit.py:1253 dcim/forms/filtersets.py:67 +#: dcim/forms/bulk_edit.py:809 dcim/forms/bulk_edit.py:994 +#: dcim/forms/bulk_edit.py:1013 dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_edit.py:1122 +#: dcim/forms/bulk_edit.py:1173 dcim/forms/bulk_edit.py:1200 +#: dcim/forms/bulk_edit.py:1227 dcim/forms/bulk_edit.py:1245 +#: dcim/forms/bulk_edit.py:1263 dcim/forms/filtersets.py:67 #: dcim/forms/object_create.py:46 templates/dcim/cable.html:32 #: templates/dcim/consoleport.html:32 templates/dcim/consoleserverport.html:32 #: templates/dcim/devicebay.html:28 templates/dcim/frontport.html:32 @@ -3516,82 +3542,82 @@ msgstr "模块类型" msgid "Label" msgstr "标记" -#: dcim/forms/bulk_edit.py:808 dcim/forms/filtersets.py:1068 +#: dcim/forms/bulk_edit.py:818 dcim/forms/filtersets.py:1068 #: templates/dcim/cable.html:50 msgid "Length" msgstr "长度" -#: dcim/forms/bulk_edit.py:813 dcim/forms/bulk_import.py:1226 +#: dcim/forms/bulk_edit.py:823 dcim/forms/bulk_import.py:1226 #: dcim/forms/bulk_import.py:1229 dcim/forms/filtersets.py:1072 msgid "Length unit" msgstr "长度单位" -#: dcim/forms/bulk_edit.py:837 templates/dcim/virtualchassis.html:23 +#: dcim/forms/bulk_edit.py:847 templates/dcim/virtualchassis.html:23 msgid "Domain" msgstr "域" -#: dcim/forms/bulk_edit.py:905 dcim/forms/bulk_import.py:1345 +#: dcim/forms/bulk_edit.py:915 dcim/forms/bulk_import.py:1345 #: dcim/forms/filtersets.py:1158 dcim/forms/model_forms.py:750 msgid "Power panel" msgstr "电源面版" -#: dcim/forms/bulk_edit.py:927 dcim/forms/bulk_import.py:1381 +#: dcim/forms/bulk_edit.py:937 dcim/forms/bulk_import.py:1381 #: dcim/forms/filtersets.py:1180 templates/dcim/powerfeed.html:83 msgid "Supply" msgstr "供应" -#: dcim/forms/bulk_edit.py:933 dcim/forms/bulk_import.py:1386 +#: dcim/forms/bulk_edit.py:943 dcim/forms/bulk_import.py:1386 #: dcim/forms/filtersets.py:1185 templates/dcim/powerfeed.html:95 msgid "Phase" msgstr "相位" -#: dcim/forms/bulk_edit.py:939 dcim/forms/filtersets.py:1190 +#: dcim/forms/bulk_edit.py:949 dcim/forms/filtersets.py:1190 #: templates/dcim/powerfeed.html:87 msgid "Voltage" msgstr "电压" -#: dcim/forms/bulk_edit.py:943 dcim/forms/filtersets.py:1194 +#: dcim/forms/bulk_edit.py:953 dcim/forms/filtersets.py:1194 #: templates/dcim/powerfeed.html:91 msgid "Amperage" msgstr "电流" -#: dcim/forms/bulk_edit.py:947 dcim/forms/filtersets.py:1198 +#: dcim/forms/bulk_edit.py:957 dcim/forms/filtersets.py:1198 msgid "Max utilization" msgstr "最大利用率" -#: dcim/forms/bulk_edit.py:1036 +#: dcim/forms/bulk_edit.py:1046 msgid "Maximum draw" msgstr "最大功率" -#: dcim/forms/bulk_edit.py:1039 dcim/models/device_component_templates.py:282 +#: dcim/forms/bulk_edit.py:1049 dcim/models/device_component_templates.py:282 #: dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "最大功率(瓦)" -#: dcim/forms/bulk_edit.py:1042 +#: dcim/forms/bulk_edit.py:1052 msgid "Allocated draw" msgstr "分配功率" -#: dcim/forms/bulk_edit.py:1045 dcim/models/device_component_templates.py:289 +#: dcim/forms/bulk_edit.py:1055 dcim/models/device_component_templates.py:289 #: dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "分配功率(瓦)" -#: dcim/forms/bulk_edit.py:1078 dcim/forms/bulk_import.py:786 +#: dcim/forms/bulk_edit.py:1088 dcim/forms/bulk_import.py:786 #: dcim/forms/model_forms.py:953 dcim/forms/model_forms.py:1278 #: dcim/forms/model_forms.py:1567 dcim/forms/object_import.py:55 msgid "Power port" msgstr "电源接口" -#: dcim/forms/bulk_edit.py:1083 dcim/forms/bulk_import.py:793 +#: dcim/forms/bulk_edit.py:1093 dcim/forms/bulk_import.py:793 msgid "Feed leg" msgstr "馈电线路" -#: dcim/forms/bulk_edit.py:1129 dcim/forms/bulk_edit.py:1440 +#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1457 msgid "Management only" msgstr "仅限管理" -#: dcim/forms/bulk_edit.py:1139 dcim/forms/bulk_edit.py:1446 +#: dcim/forms/bulk_edit.py:1149 dcim/forms/bulk_edit.py:1463 #: dcim/forms/bulk_import.py:876 dcim/forms/filtersets.py:1394 #: dcim/forms/object_import.py:90 #: dcim/models/device_component_templates.py:437 @@ -3599,7 +3625,7 @@ msgstr "仅限管理" msgid "PoE mode" msgstr "PoE模式" -#: dcim/forms/bulk_edit.py:1145 dcim/forms/bulk_edit.py:1452 +#: dcim/forms/bulk_edit.py:1155 dcim/forms/bulk_edit.py:1469 #: dcim/forms/bulk_import.py:882 dcim/forms/filtersets.py:1399 #: dcim/forms/object_import.py:95 #: dcim/models/device_component_templates.py:443 @@ -3607,12 +3633,12 @@ msgstr "PoE模式" msgid "PoE type" msgstr "PoE类型" -#: dcim/forms/bulk_edit.py:1151 dcim/forms/filtersets.py:1404 +#: dcim/forms/bulk_edit.py:1161 dcim/forms/filtersets.py:1404 #: dcim/forms/object_import.py:100 msgid "Wireless role" msgstr "无线角色" -#: dcim/forms/bulk_edit.py:1288 dcim/forms/model_forms.py:669 +#: dcim/forms/bulk_edit.py:1298 dcim/forms/model_forms.py:669 #: dcim/forms/model_forms.py:1223 dcim/tables/devices.py:313 #: templates/dcim/consoleport.html:24 templates/dcim/consoleserverport.html:24 #: templates/dcim/frontport.html:24 templates/dcim/interface.html:34 @@ -3622,16 +3648,16 @@ msgstr "无线角色" msgid "Module" msgstr "模块" -#: dcim/forms/bulk_edit.py:1420 dcim/tables/devices.py:665 +#: dcim/forms/bulk_edit.py:1437 dcim/tables/devices.py:665 #: templates/dcim/interface.html:110 msgid "LAG" msgstr "链路聚合" -#: dcim/forms/bulk_edit.py:1425 dcim/forms/model_forms.py:1305 +#: dcim/forms/bulk_edit.py:1442 dcim/forms/model_forms.py:1305 msgid "Virtual device contexts" msgstr "设备虚拟上下文" -#: dcim/forms/bulk_edit.py:1431 dcim/forms/bulk_import.py:714 +#: dcim/forms/bulk_edit.py:1448 dcim/forms/bulk_import.py:714 #: dcim/forms/bulk_import.py:740 dcim/forms/filtersets.py:1252 #: dcim/forms/filtersets.py:1277 dcim/forms/filtersets.py:1358 #: dcim/tables/devices.py:610 @@ -3640,7 +3666,7 @@ msgstr "设备虚拟上下文" msgid "Speed" msgstr "速率" -#: dcim/forms/bulk_edit.py:1460 dcim/forms/bulk_import.py:885 +#: dcim/forms/bulk_edit.py:1477 dcim/forms/bulk_import.py:885 #: templates/vpn/ikepolicy.html:25 templates/vpn/ipsecprofile.html:21 #: templates/vpn/ipsecprofile.html:48 virtualization/forms/bulk_edit.py:233 #: virtualization/forms/bulk_import.py:165 vpn/forms/bulk_edit.py:146 @@ -3651,36 +3677,44 @@ msgstr "速率" msgid "Mode" msgstr "模式" -#: dcim/forms/bulk_edit.py:1468 dcim/forms/model_forms.py:1354 +#: dcim/forms/bulk_edit.py:1485 dcim/forms/model_forms.py:1354 #: ipam/forms/bulk_import.py:178 ipam/forms/filtersets.py:498 #: ipam/models/vlans.py:84 virtualization/forms/bulk_edit.py:240 #: virtualization/forms/model_forms.py:321 msgid "VLAN group" msgstr "VLAN 组" -#: dcim/forms/bulk_edit.py:1476 dcim/forms/model_forms.py:1360 +#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1360 #: dcim/tables/devices.py:579 virtualization/forms/bulk_edit.py:248 #: virtualization/forms/model_forms.py:326 msgid "Untagged VLAN" msgstr "未标记的VLAN" -#: dcim/forms/bulk_edit.py:1484 dcim/forms/model_forms.py:1369 +#: dcim/forms/bulk_edit.py:1503 dcim/forms/model_forms.py:1369 #: dcim/tables/devices.py:585 virtualization/forms/bulk_edit.py:256 #: virtualization/forms/model_forms.py:335 msgid "Tagged VLANs" msgstr "已标记 VLANs" -#: dcim/forms/bulk_edit.py:1494 dcim/forms/model_forms.py:1341 +#: dcim/forms/bulk_edit.py:1506 +msgid "Add tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1515 +msgid "Remove tagged VLANs" +msgstr "" + +#: dcim/forms/bulk_edit.py:1531 dcim/forms/model_forms.py:1341 msgid "Wireless LAN group" msgstr "无线局域网组" -#: dcim/forms/bulk_edit.py:1499 dcim/forms/model_forms.py:1346 +#: dcim/forms/bulk_edit.py:1536 dcim/forms/model_forms.py:1346 #: dcim/tables/devices.py:619 netbox/navigation/menu.py:146 #: templates/dcim/interface.html:280 wireless/tables/wirelesslan.py:24 msgid "Wireless LANs" msgstr "无线局域网" -#: dcim/forms/bulk_edit.py:1508 dcim/forms/filtersets.py:1328 +#: dcim/forms/bulk_edit.py:1545 dcim/forms/filtersets.py:1328 #: dcim/forms/model_forms.py:1390 ipam/forms/bulk_edit.py:286 #: ipam/forms/bulk_edit.py:378 ipam/forms/filtersets.py:169 #: templates/dcim/interface.html:122 templates/ipam/prefix.html:95 @@ -3688,33 +3722,37 @@ msgstr "无线局域网" msgid "Addressing" msgstr "寻址" -#: dcim/forms/bulk_edit.py:1509 dcim/forms/filtersets.py:720 +#: dcim/forms/bulk_edit.py:1546 dcim/forms/filtersets.py:720 #: dcim/forms/model_forms.py:1391 virtualization/forms/model_forms.py:350 msgid "Operation" msgstr "操作" -#: dcim/forms/bulk_edit.py:1510 dcim/forms/filtersets.py:1329 +#: dcim/forms/bulk_edit.py:1547 dcim/forms/filtersets.py:1329 #: dcim/forms/model_forms.py:987 dcim/forms/model_forms.py:1393 msgid "PoE" msgstr "PoE" -#: dcim/forms/bulk_edit.py:1511 dcim/forms/model_forms.py:1392 +#: dcim/forms/bulk_edit.py:1548 dcim/forms/model_forms.py:1392 #: templates/dcim/interface.html:99 virtualization/forms/bulk_edit.py:267 #: virtualization/forms/model_forms.py:351 msgid "Related Interfaces" msgstr "相关接口" -#: dcim/forms/bulk_edit.py:1512 dcim/forms/model_forms.py:1394 +#: dcim/forms/bulk_edit.py:1549 dcim/forms/model_forms.py:1394 #: virtualization/forms/bulk_edit.py:268 #: virtualization/forms/model_forms.py:352 msgid "802.1Q Switching" msgstr "802.1Q 交换" -#: dcim/forms/bulk_edit.py:1574 dcim/forms/bulk_edit.py:1576 +#: dcim/forms/bulk_edit.py:1553 +msgid "Add/Remove" +msgstr "" + +#: dcim/forms/bulk_edit.py:1612 dcim/forms/bulk_edit.py:1614 msgid "Interface mode must be specified to assign VLANs" msgstr "该接口模式下,必须指定VLAN" -#: dcim/forms/bulk_edit.py:1581 dcim/forms/common.py:50 +#: dcim/forms/bulk_edit.py:1619 dcim/forms/common.py:50 msgid "An access interface cannot have tagged VLANs assigned." msgstr "access接口不允许指定Tag的VLAN" @@ -3855,26 +3893,6 @@ msgstr "指定系统平台" msgid "Virtual chassis" msgstr "堆叠" -#: dcim/forms/bulk_import.py:517 dcim/forms/filtersets.py:728 -#: dcim/forms/filtersets.py:898 dcim/forms/model_forms.py:522 -#: dcim/tables/devices.py:202 extras/filtersets.py:596 -#: extras/forms/filtersets.py:322 ipam/forms/filtersets.py:415 -#: ipam/forms/filtersets.py:447 templates/dcim/device.html:239 -#: templates/virtualization/cluster.html:10 -#: templates/virtualization/virtualmachine.html:92 -#: templates/virtualization/virtualmachine.html:101 -#: virtualization/filtersets.py:157 virtualization/filtersets.py:277 -#: virtualization/forms/bulk_edit.py:129 -#: virtualization/forms/bulk_import.py:92 -#: virtualization/forms/filtersets.py:99 -#: virtualization/forms/filtersets.py:123 -#: virtualization/forms/filtersets.py:204 -#: virtualization/forms/model_forms.py:79 -#: virtualization/forms/model_forms.py:176 -#: virtualization/tables/virtualmachines.py:67 -msgid "Cluster" -msgstr "集群" - #: dcim/forms/bulk_import.py:521 msgid "Virtualization cluster" msgstr "虚拟化集群" @@ -6466,31 +6484,31 @@ msgstr "渲染模板时出错: {error}" msgid "Virtual Machines" msgstr "虚拟机" -#: dcim/views.py:2897 +#: dcim/views.py:2907 #, python-brace-format msgid "Installed device {device} in bay {device_bay}." msgstr "已安装的设备 {device} 在海湾里 {device_bay}。" -#: dcim/views.py:2938 +#: dcim/views.py:2948 #, python-brace-format msgid "Removed device {device} from bay {device_bay}." msgstr "已移除的设备 {device} 来自海湾 {device_bay}。" -#: dcim/views.py:3044 ipam/tables/ip.py:234 +#: dcim/views.py:3054 ipam/tables/ip.py:234 msgid "Children" msgstr "子网" -#: dcim/views.py:3510 +#: dcim/views.py:3520 #, python-brace-format msgid "Added member {device}" msgstr "已添加成员 {device}" -#: dcim/views.py:3557 +#: dcim/views.py:3567 #, python-brace-format msgid "Unable to remove master device {device} from the virtual chassis." msgstr "无法移除主设备 {device} 来自虚拟机箱。" -#: dcim/views.py:3570 +#: dcim/views.py:3580 #, python-brace-format msgid "Removed {device} from virtual chassis {chassis}" msgstr "已移除 {device} 来自虚拟机箱 {chassis}" @@ -7408,19 +7426,19 @@ msgstr "在指定的时间执行脚本" msgid "Interval at which this script is re-run (in minutes)" msgstr "重新运行此脚本的间隔(分钟)" -#: extras/jobs.py:49 +#: extras/jobs.py:47 msgid "Database changes have been reverted automatically." msgstr "数据库更改已自动恢复。" -#: extras/jobs.py:55 +#: extras/jobs.py:53 msgid "Script aborted with error: " msgstr "脚本因错误而中止:" -#: extras/jobs.py:65 +#: extras/jobs.py:63 msgid "An exception occurred: " msgstr "出现异常:" -#: extras/jobs.py:70 +#: extras/jobs.py:68 msgid "Database changes have been reverted due to error." msgstr "由于出现错误,数据库更改已回滚。" @@ -8690,7 +8708,7 @@ msgstr "VLAN组" #: ipam/forms/bulk_edit.py:234 ipam/forms/bulk_import.py:185 #: ipam/forms/filtersets.py:256 ipam/forms/model_forms.py:218 -#: ipam/models/vlans.py:234 ipam/tables/ip.py:255 +#: ipam/models/vlans.py:250 ipam/tables/ip.py:255 #: templates/ipam/prefix.html:60 templates/ipam/vlan.html:12 #: templates/ipam/vlan/base.html:6 templates/ipam/vlan_edit.html:10 #: templates/wireless/wirelesslan.html:30 vpn/forms/bulk_import.py:304 @@ -8944,7 +8962,7 @@ msgstr "指定给一个接口" msgid "DNS Name" msgstr "DNS名称" -#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:235 ipam/tables/ip.py:176 +#: ipam/forms/filtersets.py:416 ipam/models/vlans.py:251 ipam/tables/ip.py:176 #: ipam/tables/vlans.py:82 ipam/views.py:971 netbox/navigation/menu.py:193 #: netbox/navigation/menu.py:195 msgid "VLANs" @@ -8954,7 +8972,7 @@ msgstr "VLANs" msgid "Contains VLAN ID" msgstr "包含 VLAN ID" -#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:176 +#: ipam/forms/filtersets.py:513 ipam/models/vlans.py:192 #: templates/ipam/vlan.html:31 msgid "VLAN ID" msgstr "VLAN ID" @@ -9392,45 +9410,55 @@ msgstr "没有作用域id,无法设置作用域。" msgid "Cannot set scope_id without scope_type." msgstr "没有作用域类型,无法设置作用域。" -#: ipam/models/vlans.py:101 +#: ipam/models/vlans.py:105 +#, python-brace-format +msgid "Starting VLAN ID in range ({value}) cannot be less than {minimum}" +msgstr "" + +#: ipam/models/vlans.py:111 +#, python-brace-format +msgid "Ending VLAN ID in range ({value}) cannot exceed {maximum}" +msgstr "" + +#: ipam/models/vlans.py:118 +#, python-brace-format +msgid "" +"Ending VLAN ID in range must be greater than or equal to the starting VLAN " +"ID ({range})" +msgstr "" + +#: ipam/models/vlans.py:124 msgid "Ranges cannot overlap." msgstr "范围不能重叠。" -#: ipam/models/vlans.py:106 -#, python-brace-format -msgid "" -"Maximum child VID must be greater than or equal to minimum child VID " -"({value})" -msgstr "儿童 VID 的最大值必须大于或等于最小孩子 VID ({value})" - -#: ipam/models/vlans.py:165 +#: ipam/models/vlans.py:181 msgid "The specific site to which this VLAN is assigned (if any)" msgstr "此VLAN所属的站点(如果有)" -#: ipam/models/vlans.py:173 +#: ipam/models/vlans.py:189 msgid "VLAN group (optional)" msgstr "VLAN组(可选)" -#: ipam/models/vlans.py:181 +#: ipam/models/vlans.py:197 msgid "Numeric VLAN ID (1-4094)" msgstr "VLAN ID(1-4094)" -#: ipam/models/vlans.py:199 +#: ipam/models/vlans.py:215 msgid "Operational status of this VLAN" msgstr "此VLAN的操作状态" -#: ipam/models/vlans.py:207 +#: ipam/models/vlans.py:223 msgid "The primary function of this VLAN" msgstr "此VLAN的主要功能" -#: ipam/models/vlans.py:250 +#: ipam/models/vlans.py:266 #, python-brace-format msgid "" "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to " "site {site}." msgstr "VLAN 已分配给组 {group}(作用域:{scope}); 不能再分配给站点:{site}。" -#: ipam/models/vlans.py:259 +#: ipam/models/vlans.py:275 #, python-brace-format msgid "VID must be in ranges {ranges} for VLANs in group {group}" msgstr "VID 必须在范围内 {ranges} 对于组中的 VLAN {group}" @@ -10163,10 +10191,6 @@ msgstr "IPSec策略" msgid "IPSec Profiles" msgstr "IPSec 配置文件" -#: netbox/navigation/menu.py:243 templates/dcim/device_edit.html:78 -msgid "Virtualization" -msgstr "虚拟化" - #: netbox/navigation/menu.py:251 #: templates/virtualization/virtualmachine.html:174 #: templates/virtualization/virtualmachine/base.html:32 @@ -10563,19 +10587,19 @@ msgstr "渲染所选导出模板时出错 ({template}): {error}" msgid "Row {i}: Object with ID {id} does not exist" msgstr "第{i}行: ID为{id}的对象不存在" -#: netbox/views/generic/bulk_views.py:702 -#: netbox/views/generic/bulk_views.py:900 -#: netbox/views/generic/bulk_views.py:948 +#: netbox/views/generic/bulk_views.py:709 +#: netbox/views/generic/bulk_views.py:907 +#: netbox/views/generic/bulk_views.py:955 #, python-brace-format msgid "No {object_type} were selected." msgstr "没有 {object_type} 被选中。" -#: netbox/views/generic/bulk_views.py:782 +#: netbox/views/generic/bulk_views.py:789 #, python-brace-format msgid "Renamed {count} {object_type}" msgstr "重命名 {count} {object_type}" -#: netbox/views/generic/bulk_views.py:878 +#: netbox/views/generic/bulk_views.py:885 #, python-brace-format msgid "Deleted {count} {object_type}" msgstr "已删除 {count} {object_type}" @@ -10607,7 +10631,7 @@ msgstr "已同步 {count} {object_type}" msgid "{class_name} must implement get_children()" msgstr "{class_name}必须实现get_children()方法" -#: netbox/views/misc.py:44 +#: netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -12434,7 +12458,7 @@ msgid "You do not have permission to run scripts" msgstr "您没有权限执行脚本" #: templates/extras/script.html:41 templates/extras/script.html:45 -#: templates/extras/script_list.html:86 +#: templates/extras/script_list.html:87 msgid "Run Script" msgstr "保存运行脚本计划" @@ -12446,27 +12470,32 @@ msgstr "加载脚本时出错" msgid "Script no longer exists in the source file." msgstr "源文件中没有该脚本。" -#: templates/extras/script_list.html:46 +#: templates/extras/script_list.html:47 msgid "Last Run" msgstr "上一次运行" -#: templates/extras/script_list.html:61 +#: templates/extras/script_list.html:62 msgid "Script is no longer present in the source file" msgstr "源文件中没有该脚本。" -#: templates/extras/script_list.html:74 +#: templates/extras/script_list.html:75 msgid "Never" msgstr "从不" -#: templates/extras/script_list.html:84 +#: templates/extras/script_list.html:85 msgid "Run Again" msgstr "重新运行" -#: templates/extras/script_list.html:138 +#: templates/extras/script_list.html:133 +#, python-format +msgid "Could not load scripts from module %(module)s" +msgstr "" + +#: templates/extras/script_list.html:141 msgid "No Scripts Found" msgstr "找不到脚本" -#: templates/extras/script_list.html:141 +#: templates/extras/script_list.html:144 #, python-format msgid "" "Get started by creating a script from " @@ -14237,13 +14266,13 @@ msgid "Memory (MB)" msgstr "内存 (MB)" #: virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" -msgstr "磁盘 (GB)" +msgid "Disk (MB)" +msgstr "" #: virtualization/forms/bulk_edit.py:334 #: virtualization/forms/filtersets.py:251 -msgid "Size (GB)" -msgstr "大小 (GB)" +msgid "Size (MB)" +msgstr "" #: virtualization/forms/bulk_import.py:44 msgid "Type of cluster" diff --git a/netbox/users/migrations/0001_squashed_0011.py b/netbox/users/migrations/0001_squashed_0011.py index cad84201c..263604d34 100644 --- a/netbox/users/migrations/0001_squashed_0011.py +++ b/netbox/users/migrations/0001_squashed_0011.py @@ -8,7 +8,6 @@ import users.models class Migration(migrations.Migration): - initial = True dependencies = [ @@ -39,15 +38,33 @@ class Migration(migrations.Migration): ('password', models.CharField(max_length=128)), ('last_login', models.DateTimeField(blank=True, null=True)), ('is_superuser', models.BooleanField(default=False)), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()])), + ( + 'username', + models.CharField( + error_messages={'unique': 'A user with that username already exists.'}, + max_length=150, + unique=True, + validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], + ), + ), ('first_name', models.CharField(blank=True, max_length=150)), ('last_name', models.CharField(blank=True, max_length=150)), ('email', models.EmailField(blank=True, max_length=254)), ('is_staff', models.BooleanField(default=False)), ('is_active', models.BooleanField(default=True)), ('date_joined', models.DateTimeField(default=django.utils.timezone.now)), - ('groups', models.ManyToManyField(blank=True, related_name='user_set', related_query_name='user', to='auth.group')), - ('user_permissions', models.ManyToManyField(blank=True, related_name='user_set', related_query_name='user', to='auth.permission')), + ( + 'groups', + models.ManyToManyField( + blank=True, related_name='user_set', related_query_name='user', to='auth.group' + ), + ), + ( + 'user_permissions', + models.ManyToManyField( + blank=True, related_name='user_set', related_query_name='user', to='auth.permission' + ), + ), ], options={ 'verbose_name': 'user', @@ -64,7 +81,12 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)), ('data', models.JSONField(default=dict)), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='config', to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, related_name='config', to=settings.AUTH_USER_MODEL + ), + ), ], options={ 'verbose_name': 'User Preferences', @@ -78,10 +100,20 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True)), ('expires', models.DateTimeField(blank=True, null=True)), - ('key', models.CharField(max_length=40, unique=True, validators=[django.core.validators.MinLengthValidator(40)])), + ( + 'key', + models.CharField( + max_length=40, unique=True, validators=[django.core.validators.MinLengthValidator(40)] + ), + ), ('write_enabled', models.BooleanField(default=True)), ('description', models.CharField(blank=True, max_length=200)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to=settings.AUTH_USER_MODEL)), + ( + 'user', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to=settings.AUTH_USER_MODEL + ), + ), ], ), migrations.CreateModel( @@ -91,11 +123,37 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=100)), ('description', models.CharField(blank=True, max_length=200)), ('enabled', models.BooleanField(default=True)), - ('actions', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=30), size=None)), + ( + 'actions', + django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=30), size=None), + ), ('constraints', models.JSONField(blank=True, null=True)), ('groups', models.ManyToManyField(blank=True, related_name='object_permissions', to='auth.Group')), - ('object_types', models.ManyToManyField(limit_choices_to=models.Q(models.Q(models.Q(('app_label__in', ['account', 'admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users']), _negated=True), models.Q(('app_label', 'auth'), ('model__in', ['group', 'user'])), models.Q(('app_label', 'users'), ('model__in', ['objectpermission', 'token'])), _connector='OR')), related_name='object_permissions', to='contenttypes.ContentType')), - ('users', models.ManyToManyField(blank=True, related_name='object_permissions', to=settings.AUTH_USER_MODEL)), + ( + 'object_types', + models.ManyToManyField( + limit_choices_to=models.Q( + models.Q( + models.Q( + ( + 'app_label__in', + ['account', 'admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users'], + ), + _negated=True, + ), + models.Q(('app_label', 'auth'), ('model__in', ['group', 'user'])), + models.Q(('app_label', 'users'), ('model__in', ['objectpermission', 'token'])), + _connector='OR', + ) + ), + related_name='object_permissions', + to='contenttypes.ContentType', + ), + ), + ( + 'users', + models.ManyToManyField(blank=True, related_name='object_permissions', to=settings.AUTH_USER_MODEL), + ), ], options={ 'verbose_name': 'permission', diff --git a/netbox/users/migrations/0002_squashed_0004.py b/netbox/users/migrations/0002_squashed_0004.py index 078721c48..275d7a7a9 100644 --- a/netbox/users/migrations/0002_squashed_0004.py +++ b/netbox/users/migrations/0002_squashed_0004.py @@ -5,11 +5,10 @@ import ipam.fields class Migration(migrations.Migration): - replaces = [ ('users', '0002_standardize_id_fields'), ('users', '0003_token_allowed_ips_last_used'), - ('users', '0004_netboxgroup_netboxuser') + ('users', '0004_netboxgroup_netboxuser'), ] dependencies = [ @@ -36,7 +35,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='token', name='allowed_ips', - field=django.contrib.postgres.fields.ArrayField(base_field=ipam.fields.IPNetworkField(), blank=True, null=True, size=None), + field=django.contrib.postgres.fields.ArrayField( + base_field=ipam.fields.IPNetworkField(), blank=True, null=True, size=None + ), ), migrations.AddField( model_name='token', @@ -45,8 +46,7 @@ class Migration(migrations.Migration): ), migrations.CreateModel( name='NetBoxGroup', - fields=[ - ], + fields=[], options={ 'verbose_name': 'Group', 'proxy': True, diff --git a/netbox/users/migrations/0005_alter_user_table.py b/netbox/users/migrations/0005_alter_user_table.py index 1163da0ae..2e9f699b3 100644 --- a/netbox/users/migrations/0005_alter_user_table.py +++ b/netbox/users/migrations/0005_alter_user_table.py @@ -19,7 +19,6 @@ def update_content_types(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('users', '0002_squashed_0004'), ('extras', '0113_customfield_rename_object_type'), @@ -33,24 +32,17 @@ class Migration(migrations.Migration): name='user', table=None, ), - # Convert the `id` column to a 64-bit integer (BigAutoField is implied by DEFAULT_AUTO_FIELD) - migrations.RunSQL("ALTER TABLE users_user ALTER COLUMN id TYPE bigint"), - + migrations.RunSQL('ALTER TABLE users_user ALTER COLUMN id TYPE bigint'), # Rename auth_user_* sequences - migrations.RunSQL("ALTER TABLE auth_user_groups_id_seq RENAME TO users_user_groups_id_seq"), - migrations.RunSQL("ALTER TABLE auth_user_id_seq RENAME TO users_user_id_seq"), - migrations.RunSQL("ALTER TABLE auth_user_user_permissions_id_seq RENAME TO users_user_user_permissions_id_seq"), - + migrations.RunSQL('ALTER TABLE auth_user_groups_id_seq RENAME TO users_user_groups_id_seq'), + migrations.RunSQL('ALTER TABLE auth_user_id_seq RENAME TO users_user_id_seq'), + migrations.RunSQL('ALTER TABLE auth_user_user_permissions_id_seq RENAME TO users_user_user_permissions_id_seq'), # Rename auth_user_* indexes - migrations.RunSQL("ALTER INDEX auth_user_pkey RENAME TO users_user_pkey"), + migrations.RunSQL('ALTER INDEX auth_user_pkey RENAME TO users_user_pkey'), # Hash is deterministic; generated via schema_editor._create_index_name() - migrations.RunSQL("ALTER INDEX auth_user_username_6821ab7c_like RENAME TO users_user_username_06e46fe6_like"), - migrations.RunSQL("ALTER INDEX auth_user_username_key RENAME TO users_user_username_key"), - + migrations.RunSQL('ALTER INDEX auth_user_username_6821ab7c_like RENAME TO users_user_username_06e46fe6_like'), + migrations.RunSQL('ALTER INDEX auth_user_username_key RENAME TO users_user_username_key'), # Update ContentTypes - migrations.RunPython( - code=update_content_types, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_content_types, reverse_code=migrations.RunPython.noop), ] diff --git a/netbox/users/migrations/0006_custom_group_model.py b/netbox/users/migrations/0006_custom_group_model.py index f958d242a..f70c1d58d 100644 --- a/netbox/users/migrations/0006_custom_group_model.py +++ b/netbox/users/migrations/0006_custom_group_model.py @@ -16,7 +16,6 @@ def update_custom_fields(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('users', '0005_alter_user_table'), ] @@ -29,7 +28,12 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=150, unique=True)), ('description', models.CharField(blank=True, max_length=200)), - ('permissions', models.ManyToManyField(blank=True, related_name='groups', related_query_name='group', to='auth.permission')), + ( + 'permissions', + models.ManyToManyField( + blank=True, related_name='groups', related_query_name='group', to='auth.permission' + ), + ), ], options={ 'ordering': ('name',), @@ -40,17 +44,10 @@ class Migration(migrations.Migration): ('objects', users.models.GroupManager()), ], ), - # Copy existing groups from the old table into the new one - migrations.RunSQL( - "INSERT INTO users_group (SELECT id, name, '' AS description FROM auth_group)" - ), - + migrations.RunSQL("INSERT INTO users_group (SELECT id, name, '' AS description FROM auth_group)"), # Update the sequence for group ID values - migrations.RunSQL( - "SELECT setval('users_group_id_seq', (SELECT MAX(id) FROM users_group))" - ), - + migrations.RunSQL("SELECT setval('users_group_id_seq', (SELECT MAX(id) FROM users_group))"), # Update the "groups" M2M fields on User & ObjectPermission migrations.AlterField( model_name='user', @@ -62,23 +59,12 @@ class Migration(migrations.Migration): name='groups', field=models.ManyToManyField(blank=True, related_name='object_permissions', to='users.group'), ), - # Delete any lingering group assignments for legacy permissions (from before NetBox v2.9) - migrations.RunSQL( - "DELETE from auth_group_permissions" - ), - + migrations.RunSQL('DELETE from auth_group_permissions'), # Delete groups from the old table - migrations.RunSQL( - "DELETE from auth_group" - ), - + migrations.RunSQL('DELETE from auth_group'), # Update custom fields - migrations.RunPython( - code=update_custom_fields, - reverse_code=migrations.RunPython.noop - ), - + migrations.RunPython(code=update_custom_fields, reverse_code=migrations.RunPython.noop), # Delete the proxy model migrations.DeleteModel( name='NetBoxGroup', diff --git a/netbox/users/migrations/0007_objectpermission_update_object_types.py b/netbox/users/migrations/0007_objectpermission_update_object_types.py index d3018a602..598b00b92 100644 --- a/netbox/users/migrations/0007_objectpermission_update_object_types.py +++ b/netbox/users/migrations/0007_objectpermission_update_object_types.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('core', '0010_gfk_indexes'), ('users', '0006_custom_group_model'), @@ -14,6 +13,23 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='objectpermission', name='object_types', - field=models.ManyToManyField(limit_choices_to=models.Q(models.Q(models.Q(('app_label__in', ['account', 'admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users']), _negated=True), models.Q(('app_label', 'auth'), ('model__in', ['group', 'user'])), models.Q(('app_label', 'users'), ('model__in', ['objectpermission', 'token'])), _connector='OR')), related_name='object_permissions', to='core.objecttype'), + field=models.ManyToManyField( + limit_choices_to=models.Q( + models.Q( + models.Q( + ( + 'app_label__in', + ['account', 'admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users'], + ), + _negated=True, + ), + models.Q(('app_label', 'auth'), ('model__in', ['group', 'user'])), + models.Q(('app_label', 'users'), ('model__in', ['objectpermission', 'token'])), + _connector='OR', + ) + ), + related_name='object_permissions', + to='core.objecttype', + ), ), ] diff --git a/netbox/users/migrations/0008_flip_objectpermission_assignments.py b/netbox/users/migrations/0008_flip_objectpermission_assignments.py index c61c8b124..11dea5819 100644 --- a/netbox/users/migrations/0008_flip_objectpermission_assignments.py +++ b/netbox/users/migrations/0008_flip_objectpermission_assignments.py @@ -2,7 +2,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('users', '0007_objectpermission_update_object_types'), ] @@ -24,52 +23,47 @@ class Migration(migrations.Migration): database_operations=[ # Rename table migrations.RunSQL( - "ALTER TABLE users_objectpermission_groups" - " RENAME TO users_group_object_permissions" + 'ALTER TABLE users_objectpermission_groups' ' RENAME TO users_group_object_permissions' ), migrations.RunSQL( - "ALTER TABLE users_objectpermission_groups_id_seq" - " RENAME TO users_group_object_permissions_id_seq" + 'ALTER TABLE users_objectpermission_groups_id_seq' + ' RENAME TO users_group_object_permissions_id_seq' ), - # Rename constraints migrations.RunSQL( - "ALTER TABLE users_group_object_permissions RENAME CONSTRAINT " - "users_objectpermissi_group_id_fb7ba6e0_fk_users_gro TO " - "users_group_object_p_group_id_90dd183a_fk_users_gro" + 'ALTER TABLE users_group_object_permissions RENAME CONSTRAINT ' + 'users_objectpermissi_group_id_fb7ba6e0_fk_users_gro TO ' + 'users_group_object_p_group_id_90dd183a_fk_users_gro' ), # Fix for #15698: Drop & recreate constraint which may not exist migrations.RunSQL( - "ALTER TABLE users_group_object_permissions DROP CONSTRAINT IF EXISTS " - "users_objectpermissi_objectpermission_id_2f7cc117_fk_users_obj" + 'ALTER TABLE users_group_object_permissions DROP CONSTRAINT IF EXISTS ' + 'users_objectpermissi_objectpermission_id_2f7cc117_fk_users_obj' ), migrations.RunSQL( - "ALTER TABLE users_group_object_permissions ADD CONSTRAINT " - "users_group_object_p_objectpermission_id_dd489dc4_fk_users_obj " - "FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) " - "DEFERRABLE INITIALLY DEFERRED" + 'ALTER TABLE users_group_object_permissions ADD CONSTRAINT ' + 'users_group_object_p_objectpermission_id_dd489dc4_fk_users_obj ' + 'FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) ' + 'DEFERRABLE INITIALLY DEFERRED' ), - # Rename indexes migrations.RunSQL( - "ALTER INDEX users_objectpermission_groups_pkey " - " RENAME TO users_group_object_permissions_pkey" + 'ALTER INDEX users_objectpermission_groups_pkey ' ' RENAME TO users_group_object_permissions_pkey' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_g_objectpermission_id_grou_3b62a39c_uniq " - " RENAME TO users_group_object_permi_group_id_objectpermissio_db1f8cbe_uniq" + 'ALTER INDEX users_objectpermission_g_objectpermission_id_grou_3b62a39c_uniq ' + ' RENAME TO users_group_object_permi_group_id_objectpermissio_db1f8cbe_uniq' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_groups_group_id_fb7ba6e0" - " RENAME TO users_group_object_permissions_group_id_90dd183a" + 'ALTER INDEX users_objectpermission_groups_group_id_fb7ba6e0' + ' RENAME TO users_group_object_permissions_group_id_90dd183a' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_groups_objectpermission_id_2f7cc117" - " RENAME TO users_group_object_permissions_objectpermission_id_dd489dc4" + 'ALTER INDEX users_objectpermission_groups_objectpermission_id_2f7cc117' + ' RENAME TO users_group_object_permissions_objectpermission_id_dd489dc4' ), - ] + ], ), - # Flip M2M assignments for ObjectPermission to Users migrations.SeparateDatabaseAndState( state_operations=[ @@ -86,49 +80,44 @@ class Migration(migrations.Migration): database_operations=[ # Rename table migrations.RunSQL( - "ALTER TABLE users_objectpermission_users" - " RENAME TO users_user_object_permissions" + 'ALTER TABLE users_objectpermission_users' ' RENAME TO users_user_object_permissions' ), migrations.RunSQL( - "ALTER TABLE users_objectpermission_users_id_seq" - " RENAME TO users_user_object_permissions_id_seq" + 'ALTER TABLE users_objectpermission_users_id_seq' ' RENAME TO users_user_object_permissions_id_seq' ), - # Rename constraints migrations.RunSQL( - "ALTER TABLE users_user_object_permissions RENAME CONSTRAINT " - "users_objectpermission_users_user_id_16c0905d_fk_auth_user_id TO " - "users_user_object_permissions_user_id_9d647aac_fk_users_user_id" + 'ALTER TABLE users_user_object_permissions RENAME CONSTRAINT ' + 'users_objectpermission_users_user_id_16c0905d_fk_auth_user_id TO ' + 'users_user_object_permissions_user_id_9d647aac_fk_users_user_id' ), # Fix for #15698: Drop & recreate constraint which may not exist migrations.RunSQL( - "ALTER TABLE users_user_object_permissions DROP CONSTRAINT IF EXISTS " - "users_objectpermissi_objectpermission_id_78a9c2e6_fk_users_obj" + 'ALTER TABLE users_user_object_permissions DROP CONSTRAINT IF EXISTS ' + 'users_objectpermissi_objectpermission_id_78a9c2e6_fk_users_obj' ), migrations.RunSQL( - "ALTER TABLE users_user_object_permissions ADD CONSTRAINT " - "users_user_object_pe_objectpermission_id_29b431b4_fk_users_obj " - "FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) " - "DEFERRABLE INITIALLY DEFERRED" + 'ALTER TABLE users_user_object_permissions ADD CONSTRAINT ' + 'users_user_object_pe_objectpermission_id_29b431b4_fk_users_obj ' + 'FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) ' + 'DEFERRABLE INITIALLY DEFERRED' ), - # Rename indexes migrations.RunSQL( - "ALTER INDEX users_objectpermission_users_pkey " - " RENAME TO users_user_object_permissions_pkey" + 'ALTER INDEX users_objectpermission_users_pkey ' ' RENAME TO users_user_object_permissions_pkey' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_u_objectpermission_id_user_3a7db108_uniq " - " RENAME TO users_user_object_permis_user_id_objectpermission_0a98550e_uniq" + 'ALTER INDEX users_objectpermission_u_objectpermission_id_user_3a7db108_uniq ' + ' RENAME TO users_user_object_permis_user_id_objectpermission_0a98550e_uniq' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_users_user_id_16c0905d" - " RENAME TO users_user_object_permissions_user_id_9d647aac" + 'ALTER INDEX users_objectpermission_users_user_id_16c0905d' + ' RENAME TO users_user_object_permissions_user_id_9d647aac' ), migrations.RunSQL( - "ALTER INDEX users_objectpermission_users_objectpermission_id_78a9c2e6" - " RENAME TO users_user_object_permissions_objectpermission_id_29b431b4" + 'ALTER INDEX users_objectpermission_users_objectpermission_id_78a9c2e6' + ' RENAME TO users_user_object_permissions_objectpermission_id_29b431b4' ), - ] + ], ), ] diff --git a/netbox/users/migrations/0009_update_group_perms.py b/netbox/users/migrations/0009_update_group_perms.py index f3b197492..7698fd1e7 100644 --- a/netbox/users/migrations/0009_update_group_perms.py +++ b/netbox/users/migrations/0009_update_group_perms.py @@ -18,17 +18,13 @@ def update_content_types(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('users', '0008_flip_objectpermission_assignments'), ] operations = [ # Update ContentTypes - migrations.RunPython( - code=update_content_types, - reverse_code=migrations.RunPython.noop - ), + migrations.RunPython(code=update_content_types, reverse_code=migrations.RunPython.noop), migrations.AlterField( model_name='objectpermission', name='object_types', diff --git a/netbox/users/tests/test_filtersets.py b/netbox/users/tests/test_filtersets.py index fdf25d970..8b683b346 100644 --- a/netbox/users/tests/test_filtersets.py +++ b/netbox/users/tests/test_filtersets.py @@ -286,9 +286,15 @@ class TokenTestCase(TestCase, BaseFilterSetTests): future_date = make_aware(datetime.datetime(3000, 1, 1)) past_date = make_aware(datetime.datetime(2000, 1, 1)) tokens = ( - Token(user=users[0], key=Token.generate_key(), expires=future_date, write_enabled=True, description='foobar1'), - Token(user=users[1], key=Token.generate_key(), expires=future_date, write_enabled=True, description='foobar2'), - Token(user=users[2], key=Token.generate_key(), expires=past_date, write_enabled=False), + Token( + user=users[0], key=Token.generate_key(), expires=future_date, write_enabled=True, description='foobar1' + ), + Token( + user=users[1], key=Token.generate_key(), expires=future_date, write_enabled=True, description='foobar2' + ), + Token( + user=users[2], key=Token.generate_key(), expires=past_date, write_enabled=False + ), ) Token.objects.bulk_create(tokens) diff --git a/netbox/users/tests/test_views.py b/netbox/users/tests/test_views.py index 8386364dd..8226a8be9 100644 --- a/netbox/users/tests/test_views.py +++ b/netbox/users/tests/test_views.py @@ -23,11 +23,16 @@ class UserTestCase( @classmethod def setUpTestData(cls): - users = ( - User(username='username1', first_name='first1', last_name='last1', email='user1@foo.com', password='pass1xxx'), - User(username='username2', first_name='first2', last_name='last2', email='user2@foo.com', password='pass2xxx'), - User(username='username3', first_name='first3', last_name='last3', email='user3@foo.com', password='pass3xxx'), + User( + username='username1', first_name='first1', last_name='last1', email='user1@foo.com', password='pass1xxx' + ), + User( + username='username2', first_name='first2', last_name='last2', email='user2@foo.com', password='pass2xxx' + ), + User( + username='username3', first_name='first3', last_name='last3', email='user3@foo.com', password='pass3xxx' + ), ) User.objects.bulk_create(users) diff --git a/netbox/users/urls.py b/netbox/users/urls.py index 0540eae1f..83f120702 100644 --- a/netbox/users/urls.py +++ b/netbox/users/urls.py @@ -1,40 +1,21 @@ from django.urls import include, path from utilities.urls import get_model_urls -from . import views +from . import views # noqa F401 app_name = 'users' urlpatterns = [ - # Tokens - path('tokens/', views.TokenListView.as_view(), name='token_list'), - path('tokens/add/', views.TokenEditView.as_view(), name='token_add'), - path('tokens/import/', views.TokenBulkImportView.as_view(), name='token_import'), - path('tokens/edit/', views.TokenBulkEditView.as_view(), name='token_bulk_edit'), - path('tokens/delete/', views.TokenBulkDeleteView.as_view(), name='token_bulk_delete'), + path('tokens/', include(get_model_urls('users', 'token', detail=False))), path('tokens//', include(get_model_urls('users', 'token'))), - # Users - path('users/', views.UserListView.as_view(), name='user_list'), - path('users/add/', views.UserEditView.as_view(), name='user_add'), - path('users/edit/', views.UserBulkEditView.as_view(), name='user_bulk_edit'), - path('users/import/', views.UserBulkImportView.as_view(), name='user_import'), - path('users/delete/', views.UserBulkDeleteView.as_view(), name='user_bulk_delete'), + path('users/', include(get_model_urls('users', 'user', detail=False))), path('users//', include(get_model_urls('users', 'user'))), - # Groups - path('groups/', views.GroupListView.as_view(), name='group_list'), - path('groups/add/', views.GroupEditView.as_view(), name='group_add'), - path('groups/edit/', views.GroupBulkEditView.as_view(), name='group_bulk_edit'), - path('groups/import/', views.GroupBulkImportView.as_view(), name='group_import'), - path('groups/delete/', views.GroupBulkDeleteView.as_view(), name='group_bulk_delete'), + path('groups/', include(get_model_urls('users', 'group', detail=False))), path('groups//', include(get_model_urls('users', 'group'))), - # Permissions - path('permissions/', views.ObjectPermissionListView.as_view(), name='objectpermission_list'), - path('permissions/add/', views.ObjectPermissionEditView.as_view(), name='objectpermission_add'), - path('permissions/edit/', views.ObjectPermissionBulkEditView.as_view(), name='objectpermission_bulk_edit'), - path('permissions/delete/', views.ObjectPermissionBulkDeleteView.as_view(), name='objectpermission_bulk_delete'), + path('permissions/', include(get_model_urls('users', 'objectpermission', detail=False))), path('permissions//', include(get_model_urls('users', 'objectpermission'))), ] diff --git a/netbox/users/views.py b/netbox/users/views.py index b2f9a8d04..904a44674 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -12,6 +12,7 @@ from .models import Group, User, ObjectPermission, Token # Tokens # +@register_model_view(Token, 'list', path='', detail=False) class TokenListView(generic.ObjectListView): queryset = Token.objects.all() filterset = filtersets.TokenFilterSet @@ -24,6 +25,7 @@ class TokenView(generic.ObjectView): queryset = Token.objects.all() +@register_model_view(Token, 'add', detail=False) @register_model_view(Token, 'edit') class TokenEditView(generic.ObjectEditView): queryset = Token.objects.all() @@ -36,17 +38,20 @@ class TokenDeleteView(generic.ObjectDeleteView): queryset = Token.objects.all() +@register_model_view(Token, 'import', detail=False) class TokenBulkImportView(generic.BulkImportView): queryset = Token.objects.all() model_form = forms.TokenImportForm +@register_model_view(Token, 'bulk_edit', path='edit', detail=False) class TokenBulkEditView(generic.BulkEditView): queryset = Token.objects.all() table = tables.TokenTable form = forms.TokenBulkEditForm +@register_model_view(Token, 'bulk_delete', path='delete', detail=False) class TokenBulkDeleteView(generic.BulkDeleteView): queryset = Token.objects.all() table = tables.TokenTable @@ -56,6 +61,7 @@ class TokenBulkDeleteView(generic.BulkDeleteView): # Users # +@register_model_view(User, 'list', path='', detail=False) class UserListView(generic.ObjectListView): queryset = User.objects.all() filterset = filtersets.UserFilterSet @@ -77,6 +83,7 @@ class UserView(generic.ObjectView): } +@register_model_view(User, 'add', detail=False) @register_model_view(User, 'edit') class UserEditView(generic.ObjectEditView): queryset = User.objects.all() @@ -88,6 +95,13 @@ class UserDeleteView(generic.ObjectDeleteView): queryset = User.objects.all() +@register_model_view(User, 'import', detail=False) +class UserBulkImportView(generic.BulkImportView): + queryset = User.objects.all() + model_form = forms.UserImportForm + + +@register_model_view(User, 'bulk_edit', path='edit', detail=False) class UserBulkEditView(generic.BulkEditView): queryset = User.objects.all() filterset = filtersets.UserFilterSet @@ -95,11 +109,7 @@ class UserBulkEditView(generic.BulkEditView): form = forms.UserBulkEditForm -class UserBulkImportView(generic.BulkImportView): - queryset = User.objects.all() - model_form = forms.UserImportForm - - +@register_model_view(User, 'bulk_delete', path='delete', detail=False) class UserBulkDeleteView(generic.BulkDeleteView): queryset = User.objects.all() filterset = filtersets.UserFilterSet @@ -110,6 +120,7 @@ class UserBulkDeleteView(generic.BulkDeleteView): # Groups # +@register_model_view(Group, 'list', path='', detail=False) class GroupListView(generic.ObjectListView): queryset = Group.objects.annotate(users_count=Count('user')).order_by('name') filterset = filtersets.GroupFilterSet @@ -123,6 +134,7 @@ class GroupView(generic.ObjectView): template_name = 'users/group.html' +@register_model_view(Group, 'add', detail=False) @register_model_view(Group, 'edit') class GroupEditView(generic.ObjectEditView): queryset = Group.objects.all() @@ -134,11 +146,13 @@ class GroupDeleteView(generic.ObjectDeleteView): queryset = Group.objects.all() +@register_model_view(Group, 'import', detail=False) class GroupBulkImportView(generic.BulkImportView): queryset = Group.objects.all() model_form = forms.GroupImportForm +@register_model_view(Group, 'bulk_edit', path='edit', detail=False) class GroupBulkEditView(generic.BulkEditView): queryset = Group.objects.all() filterset = filtersets.GroupFilterSet @@ -146,6 +160,7 @@ class GroupBulkEditView(generic.BulkEditView): form = forms.GroupBulkEditForm +@register_model_view(Group, 'bulk_delete', path='delete', detail=False) class GroupBulkDeleteView(generic.BulkDeleteView): queryset = Group.objects.annotate(users_count=Count('user')).order_by('name') filterset = filtersets.GroupFilterSet @@ -156,6 +171,7 @@ class GroupBulkDeleteView(generic.BulkDeleteView): # ObjectPermissions # +@register_model_view(ObjectPermission, 'list', path='', detail=False) class ObjectPermissionListView(generic.ObjectListView): queryset = ObjectPermission.objects.all() filterset = filtersets.ObjectPermissionFilterSet @@ -169,6 +185,7 @@ class ObjectPermissionView(generic.ObjectView): template_name = 'users/objectpermission.html' +@register_model_view(ObjectPermission, 'add', detail=False) @register_model_view(ObjectPermission, 'edit') class ObjectPermissionEditView(generic.ObjectEditView): queryset = ObjectPermission.objects.all() @@ -180,6 +197,7 @@ class ObjectPermissionDeleteView(generic.ObjectDeleteView): queryset = ObjectPermission.objects.all() +@register_model_view(ObjectPermission, 'bulk_edit', path='edit', detail=False) class ObjectPermissionBulkEditView(generic.BulkEditView): queryset = ObjectPermission.objects.all() filterset = filtersets.ObjectPermissionFilterSet @@ -187,6 +205,7 @@ class ObjectPermissionBulkEditView(generic.BulkEditView): form = forms.ObjectPermissionBulkEditForm +@register_model_view(ObjectPermission, 'bulk_delete', path='delete', detail=False) class ObjectPermissionBulkDeleteView(generic.BulkDeleteView): queryset = ObjectPermission.objects.all() filterset = filtersets.ObjectPermissionFilterSet diff --git a/netbox/utilities/conversion.py b/netbox/utilities/conversion.py index ee0175e7c..6ce32212a 100644 --- a/netbox/utilities/conversion.py +++ b/netbox/utilities/conversion.py @@ -11,9 +11,9 @@ __all__ = ( ) -def to_grams(weight, unit): +def to_grams(weight, unit) -> int: """ - Convert the given weight to kilograms. + Convert the given weight to integer grams. """ try: if weight < 0: @@ -22,13 +22,13 @@ def to_grams(weight, unit): raise TypeError(_("Invalid value '{weight}' for weight (must be a number)").format(weight=weight)) if unit == WeightUnitChoices.UNIT_KILOGRAM: - return weight * 1000 + return int(weight * 1000) if unit == WeightUnitChoices.UNIT_GRAM: - return weight + return int(weight) if unit == WeightUnitChoices.UNIT_POUND: - return weight * Decimal(453.592) + return int(weight * Decimal(453.592)) if unit == WeightUnitChoices.UNIT_OUNCE: - return weight * Decimal(28.3495) + return int(weight * Decimal(28.3495)) raise ValueError( _("Unknown unit {unit}. Must be one of the following: {valid_units}").format( unit=unit, diff --git a/netbox/utilities/forms/fields/dynamic.py b/netbox/utilities/forms/fields/dynamic.py index 6666c0e4d..13d5ffc70 100644 --- a/netbox/utilities/forms/fields/dynamic.py +++ b/netbox/utilities/forms/fields/dynamic.py @@ -2,7 +2,7 @@ import django_filters from django import forms from django.conf import settings from django.forms import BoundField -from django.urls import reverse +from django.urls import reverse, reverse_lazy from utilities.forms import widgets from utilities.views import get_viewname @@ -66,6 +66,8 @@ class DynamicModelChoiceMixin: choice (DEPRECATED: pass `context={'disabled': '$fieldname'}` instead) context: A mapping of