mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-10 13:52:17 -06:00
Compare commits
14 Commits
32fb3869a4
...
fix-19669-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef7880a013 | ||
|
|
8fd8493d11 | ||
|
|
db805053d9 | ||
|
|
cf4db67e0b | ||
|
|
f48e1cb534 | ||
|
|
ffa9a52667 | ||
|
|
47320f9958 | ||
|
|
d08a1bd07d | ||
|
|
14c4aeca54 | ||
|
|
26bec1275f | ||
|
|
fa2d7f6516 | ||
|
|
d571cb4867 | ||
|
|
2129355c30 | ||
|
|
c40bfb1445 |
@@ -302,13 +302,6 @@ Quit the server with CONTROL-C.
|
||||
|
||||
Next, connect to the name or IP of the server (as defined in `ALLOWED_HOSTS`) on port 8000; for example, <http://127.0.0.1:8000/>. You should be greeted with the NetBox home page. Try logging in using the username and password specified when creating a superuser.
|
||||
|
||||
!!! note
|
||||
By default RHEL based distros will likely block your testing attempts with firewalld. The development server port can be opened with `firewall-cmd` (add `--permanent` if you want the rule to survive server restarts):
|
||||
|
||||
```no-highlight
|
||||
firewall-cmd --zone=public --add-port=8000/tcp
|
||||
```
|
||||
|
||||
!!! danger "Not for production use"
|
||||
The development server is for development and testing purposes only. It is neither performant nor secure enough for production use. **Do not use it in production.**
|
||||
|
||||
|
||||
@@ -80,18 +80,20 @@ GET /api/ipam/vlans/?vid__gt=900
|
||||
|
||||
String based (char) fields (Name, Address, etc) support these lookup expressions:
|
||||
|
||||
| Filter | Description |
|
||||
|---------|----------------------------------------|
|
||||
| `n` | Not equal to |
|
||||
| `ic` | Contains (case-insensitive) |
|
||||
| `nic` | Does not contain (case-insensitive) |
|
||||
| `isw` | Starts with (case-insensitive) |
|
||||
| `nisw` | Does not start with (case-insensitive) |
|
||||
| `iew` | Ends with (case-insensitive) |
|
||||
| `niew` | Does not end with (case-insensitive) |
|
||||
| `ie` | Exact match (case-insensitive) |
|
||||
| `nie` | Inverse exact match (case-insensitive) |
|
||||
| `empty` | Is empty/null (boolean) |
|
||||
| Filter | Description |
|
||||
|----------|----------------------------------------|
|
||||
| `n` | Not equal to |
|
||||
| `ic` | Contains (case-insensitive) |
|
||||
| `nic` | Does not contain (case-insensitive) |
|
||||
| `isw` | Starts with (case-insensitive) |
|
||||
| `nisw` | Does not start with (case-insensitive) |
|
||||
| `iew` | Ends with (case-insensitive) |
|
||||
| `niew` | Does not end with (case-insensitive) |
|
||||
| `ie` | Exact match (case-insensitive) |
|
||||
| `nie` | Inverse exact match (case-insensitive) |
|
||||
| `empty` | Is empty/null (boolean) |
|
||||
| `regex` | Regexp matching |
|
||||
| `iregex` | Regexp matching (case-insensitive) |
|
||||
|
||||
Here is an example of a lookup expression on a string field that will return all devices with `switch` in the name:
|
||||
|
||||
|
||||
@@ -1335,6 +1335,13 @@ class MACAddressImportForm(NetBoxModelImportForm):
|
||||
|
||||
class CableImportForm(NetBoxModelImportForm):
|
||||
# Termination A
|
||||
side_a_site = CSVModelChoiceField(
|
||||
label=_('Side A site'),
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
help_text=_('Site of parent device A (if any)'),
|
||||
)
|
||||
side_a_device = CSVModelChoiceField(
|
||||
label=_('Side A device'),
|
||||
queryset=Device.objects.all(),
|
||||
@@ -1353,6 +1360,13 @@ class CableImportForm(NetBoxModelImportForm):
|
||||
)
|
||||
|
||||
# Termination B
|
||||
side_b_site = CSVModelChoiceField(
|
||||
label=_('Side B site'),
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
help_text=_('Site of parent device B (if any)'),
|
||||
)
|
||||
side_b_device = CSVModelChoiceField(
|
||||
label=_('Side B device'),
|
||||
queryset=Device.objects.all(),
|
||||
@@ -1396,14 +1410,39 @@ class CableImportForm(NetBoxModelImportForm):
|
||||
required=False,
|
||||
help_text=_('Length unit')
|
||||
)
|
||||
color = forms.CharField(
|
||||
label=_('Color'),
|
||||
required=False,
|
||||
max_length=16,
|
||||
help_text=_('Color name (e.g. "Red") or hex code (e.g. "f44336")')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Cable
|
||||
fields = [
|
||||
'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type',
|
||||
'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags',
|
||||
'side_a_site', 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_site', 'side_b_device', 'side_b_type',
|
||||
'side_b_name', 'type', 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description',
|
||||
'comments', 'tags',
|
||||
]
|
||||
|
||||
def __init__(self, data=None, *args, **kwargs):
|
||||
super().__init__(data, *args, **kwargs)
|
||||
|
||||
if data:
|
||||
# Limit choices for side_a_device to the assigned side_a_site
|
||||
if side_a_site := data.get('side_a_site'):
|
||||
side_a_device_params = {f'site__{self.fields["side_a_site"].to_field_name}': side_a_site}
|
||||
self.fields['side_a_device'].queryset = self.fields['side_a_device'].queryset.filter(
|
||||
**side_a_device_params
|
||||
)
|
||||
|
||||
# Limit choices for side_b_device to the assigned side_b_site
|
||||
if side_b_site := data.get('side_b_site'):
|
||||
side_b_device_params = {f'site__{self.fields["side_b_site"].to_field_name}': side_b_site}
|
||||
self.fields['side_b_device'].queryset = self.fields['side_b_device'].queryset.filter(
|
||||
**side_b_device_params
|
||||
)
|
||||
|
||||
def _clean_side(self, side):
|
||||
"""
|
||||
Derive a Cable's A/B termination objects.
|
||||
@@ -1440,6 +1479,24 @@ class CableImportForm(NetBoxModelImportForm):
|
||||
setattr(self.instance, f'{side}_terminations', [termination_object])
|
||||
return termination_object
|
||||
|
||||
def _clean_color(self, color):
|
||||
"""
|
||||
Derive a colors hex code
|
||||
|
||||
:param color: color as hex or color name
|
||||
"""
|
||||
color_parsed = color.strip().lower()
|
||||
|
||||
for hex_code, label in ColorChoices.CHOICES:
|
||||
if color.lower() == label.lower():
|
||||
color_parsed = hex_code
|
||||
|
||||
if len(color_parsed) > 6:
|
||||
raise forms.ValidationError(
|
||||
_(f"{color} did not match any used color name and was longer than six characters: invalid hex.")
|
||||
)
|
||||
return color_parsed
|
||||
|
||||
def clean_side_a_name(self):
|
||||
return self._clean_side('a')
|
||||
|
||||
@@ -1451,11 +1508,14 @@ class CableImportForm(NetBoxModelImportForm):
|
||||
length_unit = self.cleaned_data.get('length_unit', None)
|
||||
return length_unit if length_unit is not None else ''
|
||||
|
||||
|
||||
def clean_color(self):
|
||||
color = self.cleaned_data.get('color', None)
|
||||
return self._clean_color(color) if color is not None else ''
|
||||
#
|
||||
# Virtual chassis
|
||||
#
|
||||
|
||||
|
||||
class VirtualChassisImportForm(NetBoxModelImportForm):
|
||||
master = CSVModelChoiceField(
|
||||
label=_('Master'),
|
||||
|
||||
@@ -3,6 +3,7 @@ import svgwrite
|
||||
from svgwrite.container import Hyperlink
|
||||
from svgwrite.image import Image
|
||||
from svgwrite.gradients import LinearGradient
|
||||
from svgwrite.masking import ClipPath
|
||||
from svgwrite.shapes import Rect
|
||||
from svgwrite.text import Text
|
||||
|
||||
@@ -67,6 +68,20 @@ def get_device_description(device):
|
||||
return description
|
||||
|
||||
|
||||
def truncate_text(text, width, font_size=15):
|
||||
"""
|
||||
Truncate text to fit within the width of a rectangle.
|
||||
|
||||
:param text: The text to truncate
|
||||
:param width: Width of rectangle
|
||||
:param font_size: Font size (default is 15, ~0.875rem)
|
||||
"""
|
||||
char_width = font_size * 0.6 # 0.6 is an approximation of the average character width in pixels
|
||||
max_char = int(width / char_width)
|
||||
|
||||
return text if len(text) <= max_char else text[:max_char] + '...'
|
||||
|
||||
|
||||
class RackElevationSVG:
|
||||
"""
|
||||
Use this class to render a rack elevation as an SVG image.
|
||||
@@ -177,12 +192,26 @@ class RackElevationSVG:
|
||||
link = Hyperlink(href=f'{self.base_url}{device.get_absolute_url()}', target="_parent")
|
||||
link.set_desc(description)
|
||||
|
||||
# Create clipPath element
|
||||
# This is necessary as fallback because the truncate_text method is an approximation
|
||||
clip_id = f"clip-{device.id}"
|
||||
clip_path = ClipPath(id=clip_id)
|
||||
clip_path.add(Rect(coords, size))
|
||||
|
||||
self.drawing.defs.add(clip_path)
|
||||
|
||||
# Name to display
|
||||
display_name = truncate_text(name, size[0])
|
||||
|
||||
# Add rect element to hyperlink
|
||||
if color:
|
||||
link.add(Rect(coords, size, style=f'fill: #{color}', class_=f'slot{css_extra}'))
|
||||
else:
|
||||
link.add(Rect(coords, size, class_=f'slot blocked{css_extra}'))
|
||||
link.add(Text(name, insert=text_coords, fill=text_color, class_=f'label{css_extra}'))
|
||||
link.add(
|
||||
Text(display_name, insert=text_coords, fill=text_color, clip_path=f"url(#{clip_id})",
|
||||
class_=f'label{css_extra}')
|
||||
)
|
||||
|
||||
# Embed device type image if provided
|
||||
if self.include_images and image:
|
||||
|
||||
@@ -3266,17 +3266,27 @@ class CableTestCase(
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
site = Site.objects.create(name='Site 1', slug='site-1')
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1'),
|
||||
Site(name='Site 2', slug='site-2'),
|
||||
)
|
||||
Site.objects.bulk_create(sites)
|
||||
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
|
||||
devicetype = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
|
||||
role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
|
||||
vc = VirtualChassis.objects.create(name='Virtual Chassis')
|
||||
|
||||
# NOTE: By design, NetBox now allows for the creation of devices with the same name if they belong to
|
||||
# different sites.
|
||||
# The CSV test below demonstrates that devices with identical names on different sites can be created
|
||||
# and referenced successfully.
|
||||
devices = (
|
||||
Device(name='Device 1', site=site, device_type=devicetype, role=role),
|
||||
Device(name='Device 2', site=site, device_type=devicetype, role=role),
|
||||
Device(name='Device 3', site=site, device_type=devicetype, role=role),
|
||||
Device(name='Device 4', site=site, device_type=devicetype, role=role),
|
||||
# Create 'Device 1' assigned to 'Site 1'
|
||||
Device(name='Device 1', site=sites[0], device_type=devicetype, role=role),
|
||||
Device(name='Device 2', site=sites[0], device_type=devicetype, role=role),
|
||||
Device(name='Device 3', site=sites[0], device_type=devicetype, role=role),
|
||||
# Create 'Device 1' assigned to 'Site 2' (allowed since the site is different)
|
||||
Device(name='Device 1', site=sites[1], device_type=devicetype, role=role),
|
||||
)
|
||||
Device.objects.bulk_create(devices)
|
||||
|
||||
@@ -3327,13 +3337,15 @@ class CableTestCase(
|
||||
'tags': [t.pk for t in tags],
|
||||
}
|
||||
|
||||
# Ensure that CSV bulk import supports assigning terminations from parent devices that share
|
||||
# the same device name, provided those devices belong to different sites.
|
||||
cls.csv_data = (
|
||||
"side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name",
|
||||
"Device 3,dcim.interface,Interface 1,Device 4,dcim.interface,Interface 1",
|
||||
"Device 3,dcim.interface,Interface 2,Device 4,dcim.interface,Interface 2",
|
||||
"Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3",
|
||||
"Device 1,dcim.interface,Device 2 Interface,Device 4,dcim.interface,Interface 4",
|
||||
"Device 1,dcim.interface,Device 3 Interface,Device 4,dcim.interface,Interface 5",
|
||||
"side_a_site,side_a_device,side_a_type,side_a_name,side_b_site,side_b_device,side_b_type,side_b_name",
|
||||
"Site 1,Device 3,dcim.interface,Interface 1,Site 2,Device 1,dcim.interface,Interface 1",
|
||||
"Site 1,Device 3,dcim.interface,Interface 2,Site 2,Device 1,dcim.interface,Interface 2",
|
||||
"Site 1,Device 3,dcim.interface,Interface 3,Site 2,Device 1,dcim.interface,Interface 3",
|
||||
"Site 1,Device 1,dcim.interface,Device 2 Interface,Site 2,Device 1,dcim.interface,Interface 4",
|
||||
"Site 1,Device 1,dcim.interface,Device 3 Interface,Site 2,Device 1,dcim.interface,Interface 5",
|
||||
)
|
||||
|
||||
cls.csv_update_data = (
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.static import serve
|
||||
from django_rq.queues import get_connection
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
from rest_framework import status
|
||||
@@ -200,6 +202,17 @@ class ImageAttachmentViewSet(NetBoxModelViewSet):
|
||||
serializer_class = serializers.ImageAttachmentSerializer
|
||||
filterset_class = filtersets.ImageAttachmentFilterSet
|
||||
|
||||
@action(
|
||||
methods=['GET'],
|
||||
detail=True,
|
||||
url_path='download',
|
||||
url_name='download',
|
||||
)
|
||||
def download(self, request, pk, *args, **kwargs):
|
||||
obj = get_object_or_404(self.queryset, pk=pk)
|
||||
# Render and return the elevation as an SVG drawing with the correct content type
|
||||
return serve(request, obj.image.name, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
|
||||
#
|
||||
# Journal entries
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import datetime
|
||||
|
||||
from PIL import Image
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.base import File
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import make_aware, now
|
||||
from rest_framework import status
|
||||
@@ -616,6 +618,38 @@ class ImageAttachmentTest(
|
||||
)
|
||||
ImageAttachment.objects.bulk_create(image_attachments)
|
||||
|
||||
def test_image_download(self):
|
||||
self.add_permissions('extras.view_imageattachment')
|
||||
ct = ContentType.objects.get_for_model(Site)
|
||||
site = Site.objects.get(name='Site 1', slug='site-1')
|
||||
|
||||
image = Image.new('RGB', size=(1, 1), color=(255, 0, 0))
|
||||
image.save('test_image_download.png', format='PNG')
|
||||
image_file = File(open('test_image_download.png', 'rb'))
|
||||
content = image_file.read()
|
||||
|
||||
attachment = ImageAttachment(
|
||||
object_type=ct,
|
||||
object_id=site.pk,
|
||||
name='Image Attachment 4',
|
||||
image_height=1,
|
||||
image_width=1
|
||||
)
|
||||
attachment.image.save('test_image_download.png', image_file, save=True)
|
||||
attachment.save()
|
||||
|
||||
image = ImageAttachment.objects.get(name='Image Attachment 4')
|
||||
url = reverse('extras-api:imageattachment-download', kwargs={'pk': image.pk})
|
||||
response = self.client.get(url, **self.header)
|
||||
downloaded_content = b''.join(response.streaming_content)
|
||||
|
||||
self.assertEqual(response.headers.get('Content-Type'), 'image/png')
|
||||
self.assertEqual(response.headers.get('Content-Length'), '69')
|
||||
self.assertEqual(
|
||||
response.headers.get('Content-Disposition'), f'inline; filename="site_{site.pk}_Image_Attachment_4.png"'
|
||||
)
|
||||
self.assertEqual(content, downloaded_content)
|
||||
|
||||
|
||||
class JournalEntryTest(APIViewTestCases.APIViewTestCase):
|
||||
model = JournalEntry
|
||||
|
||||
2
netbox/project-static/dist/netbox.js
vendored
2
netbox/project-static/dist/netbox.js
vendored
File diff suppressed because one or more lines are too long
6
netbox/project-static/dist/netbox.js.map
vendored
6
netbox/project-static/dist/netbox.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -35,7 +35,7 @@ function showRackElements(
|
||||
selector: string,
|
||||
elevation: HTMLObjectElement,
|
||||
): void {
|
||||
const elements = elevation.contentDocument?.querySelectorAll(selector) ?? [];
|
||||
const elements = elevation.querySelectorAll(selector) ?? [];
|
||||
for (const element of elements) {
|
||||
element.classList.remove('hidden');
|
||||
}
|
||||
@@ -45,7 +45,7 @@ function hideRackElements(
|
||||
selector: string,
|
||||
elevation: HTMLObjectElement,
|
||||
): void {
|
||||
const elements = elevation.contentDocument?.querySelectorAll(selector) ?? [];
|
||||
const elements = elevation.querySelectorAll(selector) ?? [];
|
||||
for (const element of elements) {
|
||||
element.classList.add('hidden');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
<div style="margin-left: -30px">
|
||||
<div style="margin-left: -30px" class="rack_elevation">
|
||||
<div
|
||||
hx-get="{% url 'dcim-api:rack-elevation' pk=object.pk %}?face={{ face }}&render=svg{% if extra_params %}&{{ extra_params }}{% endif %}"
|
||||
hx-trigger="intersect"
|
||||
|
||||
@@ -45,12 +45,17 @@ class TenantBulkEditForm(NetBoxModelBulkEditForm):
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False
|
||||
)
|
||||
description = forms.CharField(
|
||||
label=_('Description'),
|
||||
max_length=200,
|
||||
required=False
|
||||
)
|
||||
|
||||
model = Tenant
|
||||
fieldsets = (
|
||||
FieldSet('group'),
|
||||
FieldSet('group', 'description'),
|
||||
)
|
||||
nullable_fields = ('group',)
|
||||
nullable_fields = ('group', 'description')
|
||||
|
||||
|
||||
#
|
||||
|
||||
@@ -98,6 +98,7 @@ class TenantTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
|
||||
cls.bulk_edit_data = {
|
||||
'group': tenant_groups[1].pk,
|
||||
'description': 'Bulk edit description',
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-07-16 05:05+0000\n"
|
||||
"POT-Creation-Date: 2025-07-24 05:05+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -215,8 +215,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:344 netbox/dcim/forms/bulk_edit.py:730
|
||||
#: netbox/dcim/forms/bulk_edit.py:935 netbox/dcim/forms/bulk_import.py:134
|
||||
#: netbox/dcim/forms/bulk_import.py:236 netbox/dcim/forms/bulk_import.py:337
|
||||
#: netbox/dcim/forms/bulk_import.py:598 netbox/dcim/forms/bulk_import.py:1479
|
||||
#: netbox/dcim/forms/bulk_import.py:1507 netbox/dcim/forms/filtersets.py:89
|
||||
#: netbox/dcim/forms/bulk_import.py:598 netbox/dcim/forms/bulk_import.py:1512
|
||||
#: netbox/dcim/forms/bulk_import.py:1540 netbox/dcim/forms/filtersets.py:89
|
||||
#: netbox/dcim/forms/filtersets.py:227 netbox/dcim/forms/filtersets.py:344
|
||||
#: netbox/dcim/forms/filtersets.py:441 netbox/dcim/forms/filtersets.py:773
|
||||
#: netbox/dcim/forms/filtersets.py:992 netbox/dcim/forms/filtersets.py:1065
|
||||
@@ -587,9 +587,10 @@ msgstr ""
|
||||
#: netbox/templates/wireless/wirelesslan.html:34
|
||||
#: netbox/templates/wireless/wirelesslangroup.html:33
|
||||
#: netbox/templates/wireless/wirelesslink.html:34
|
||||
#: netbox/tenancy/forms/bulk_edit.py:32 netbox/tenancy/forms/bulk_edit.py:82
|
||||
#: netbox/tenancy/forms/bulk_edit.py:130 netbox/users/forms/bulk_edit.py:64
|
||||
#: netbox/users/forms/bulk_edit.py:82 netbox/users/forms/bulk_edit.py:112
|
||||
#: netbox/tenancy/forms/bulk_edit.py:32 netbox/tenancy/forms/bulk_edit.py:49
|
||||
#: netbox/tenancy/forms/bulk_edit.py:87 netbox/tenancy/forms/bulk_edit.py:135
|
||||
#: netbox/users/forms/bulk_edit.py:64 netbox/users/forms/bulk_edit.py:82
|
||||
#: netbox/users/forms/bulk_edit.py:112
|
||||
#: netbox/virtualization/forms/bulk_edit.py:33
|
||||
#: netbox/virtualization/forms/bulk_edit.py:47
|
||||
#: netbox/virtualization/forms/bulk_edit.py:82
|
||||
@@ -692,8 +693,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:766 netbox/dcim/forms/bulk_import.py:792
|
||||
#: netbox/dcim/forms/bulk_import.py:818 netbox/dcim/forms/bulk_import.py:838
|
||||
#: netbox/dcim/forms/bulk_import.py:924 netbox/dcim/forms/bulk_import.py:1018
|
||||
#: netbox/dcim/forms/bulk_import.py:1060 netbox/dcim/forms/bulk_import.py:1381
|
||||
#: netbox/dcim/forms/bulk_import.py:1544 netbox/dcim/forms/filtersets.py:1023
|
||||
#: netbox/dcim/forms/bulk_import.py:1060 netbox/dcim/forms/bulk_import.py:1395
|
||||
#: netbox/dcim/forms/bulk_import.py:1577 netbox/dcim/forms/filtersets.py:1023
|
||||
#: netbox/dcim/forms/filtersets.py:1122 netbox/dcim/forms/filtersets.py:1243
|
||||
#: netbox/dcim/forms/filtersets.py:1315 netbox/dcim/forms/filtersets.py:1340
|
||||
#: netbox/dcim/forms/filtersets.py:1364 netbox/dcim/forms/filtersets.py:1384
|
||||
@@ -763,8 +764,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:1819 netbox/dcim/forms/bulk_import.py:91
|
||||
#: netbox/dcim/forms/bulk_import.py:150 netbox/dcim/forms/bulk_import.py:254
|
||||
#: netbox/dcim/forms/bulk_import.py:563 netbox/dcim/forms/bulk_import.py:717
|
||||
#: netbox/dcim/forms/bulk_import.py:1168 netbox/dcim/forms/bulk_import.py:1375
|
||||
#: netbox/dcim/forms/bulk_import.py:1539 netbox/dcim/forms/bulk_import.py:1603
|
||||
#: netbox/dcim/forms/bulk_import.py:1168 netbox/dcim/forms/bulk_import.py:1389
|
||||
#: netbox/dcim/forms/bulk_import.py:1572 netbox/dcim/forms/bulk_import.py:1636
|
||||
#: netbox/dcim/forms/filtersets.py:180 netbox/dcim/forms/filtersets.py:239
|
||||
#: netbox/dcim/forms/filtersets.py:361 netbox/dcim/forms/filtersets.py:819
|
||||
#: netbox/dcim/forms/filtersets.py:944 netbox/dcim/forms/filtersets.py:1026
|
||||
@@ -841,8 +842,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:856 netbox/dcim/forms/bulk_edit.py:1824
|
||||
#: netbox/dcim/forms/bulk_import.py:110 netbox/dcim/forms/bulk_import.py:155
|
||||
#: netbox/dcim/forms/bulk_import.py:247 netbox/dcim/forms/bulk_import.py:362
|
||||
#: netbox/dcim/forms/bulk_import.py:537 netbox/dcim/forms/bulk_import.py:1387
|
||||
#: netbox/dcim/forms/bulk_import.py:1596 netbox/dcim/forms/filtersets.py:175
|
||||
#: netbox/dcim/forms/bulk_import.py:537 netbox/dcim/forms/bulk_import.py:1401
|
||||
#: netbox/dcim/forms/bulk_import.py:1629 netbox/dcim/forms/filtersets.py:175
|
||||
#: netbox/dcim/forms/filtersets.py:207 netbox/dcim/forms/filtersets.py:325
|
||||
#: netbox/dcim/forms/filtersets.py:401 netbox/dcim/forms/filtersets.py:422
|
||||
#: netbox/dcim/forms/filtersets.py:742 netbox/dcim/forms/filtersets.py:936
|
||||
@@ -1012,7 +1013,7 @@ msgstr ""
|
||||
|
||||
#: netbox/circuits/forms/bulk_edit.py:215
|
||||
#: netbox/circuits/forms/model_forms.py:171
|
||||
#: netbox/dcim/forms/bulk_import.py:1348 netbox/dcim/forms/bulk_import.py:1366
|
||||
#: netbox/dcim/forms/bulk_import.py:1355 netbox/dcim/forms/bulk_import.py:1380
|
||||
msgid "Termination type"
|
||||
msgstr ""
|
||||
|
||||
@@ -1065,7 +1066,7 @@ msgstr ""
|
||||
#: netbox/templates/dcim/virtualchassis.html:68
|
||||
#: netbox/templates/dcim/virtualchassis_edit.html:60
|
||||
#: netbox/templates/ipam/inc/panels/fhrp_groups.html:26
|
||||
#: netbox/tenancy/forms/bulk_edit.py:159 netbox/tenancy/forms/filtersets.py:110
|
||||
#: netbox/tenancy/forms/bulk_edit.py:164 netbox/tenancy/forms/filtersets.py:110
|
||||
msgid "Priority"
|
||||
msgstr ""
|
||||
|
||||
@@ -1116,7 +1117,7 @@ msgstr ""
|
||||
#: netbox/templates/virtualization/virtualmachine.html:23
|
||||
#: netbox/templates/vpn/tunneltermination.html:17
|
||||
#: netbox/templates/wireless/inc/wirelesslink_interface.html:20
|
||||
#: netbox/tenancy/forms/bulk_edit.py:154 netbox/tenancy/forms/filtersets.py:107
|
||||
#: netbox/tenancy/forms/bulk_edit.py:159 netbox/tenancy/forms/filtersets.py:107
|
||||
#: netbox/tenancy/forms/model_forms.py:139
|
||||
#: netbox/tenancy/tables/contacts.py:110
|
||||
#: netbox/virtualization/forms/bulk_edit.py:127
|
||||
@@ -1148,7 +1149,7 @@ msgstr ""
|
||||
#: netbox/circuits/forms/bulk_import.py:229 netbox/dcim/forms/bulk_import.py:93
|
||||
#: netbox/dcim/forms/bulk_import.py:152 netbox/dcim/forms/bulk_import.py:256
|
||||
#: netbox/dcim/forms/bulk_import.py:565 netbox/dcim/forms/bulk_import.py:719
|
||||
#: netbox/dcim/forms/bulk_import.py:1170 netbox/dcim/forms/bulk_import.py:1541
|
||||
#: netbox/dcim/forms/bulk_import.py:1170 netbox/dcim/forms/bulk_import.py:1574
|
||||
#: netbox/ipam/forms/bulk_import.py:197 netbox/ipam/forms/bulk_import.py:265
|
||||
#: netbox/ipam/forms/bulk_import.py:301 netbox/ipam/forms/bulk_import.py:498
|
||||
#: netbox/ipam/forms/bulk_import.py:511
|
||||
@@ -1164,8 +1165,8 @@ msgstr ""
|
||||
#: netbox/circuits/forms/bulk_import.py:236
|
||||
#: netbox/dcim/forms/bulk_import.py:114 netbox/dcim/forms/bulk_import.py:159
|
||||
#: netbox/dcim/forms/bulk_import.py:366 netbox/dcim/forms/bulk_import.py:541
|
||||
#: netbox/dcim/forms/bulk_import.py:1391 netbox/dcim/forms/bulk_import.py:1536
|
||||
#: netbox/dcim/forms/bulk_import.py:1600 netbox/ipam/forms/bulk_import.py:45
|
||||
#: netbox/dcim/forms/bulk_import.py:1405 netbox/dcim/forms/bulk_import.py:1569
|
||||
#: netbox/dcim/forms/bulk_import.py:1633 netbox/ipam/forms/bulk_import.py:45
|
||||
#: netbox/ipam/forms/bulk_import.py:74 netbox/ipam/forms/bulk_import.py:102
|
||||
#: netbox/ipam/forms/bulk_import.py:122 netbox/ipam/forms/bulk_import.py:142
|
||||
#: netbox/ipam/forms/bulk_import.py:171 netbox/ipam/forms/bulk_import.py:260
|
||||
@@ -1245,8 +1246,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:466 netbox/dcim/forms/bulk_edit.py:735
|
||||
#: netbox/dcim/forms/bulk_edit.py:790 netbox/dcim/forms/bulk_edit.py:944
|
||||
#: netbox/dcim/forms/bulk_import.py:241 netbox/dcim/forms/bulk_import.py:343
|
||||
#: netbox/dcim/forms/bulk_import.py:604 netbox/dcim/forms/bulk_import.py:1485
|
||||
#: netbox/dcim/forms/bulk_import.py:1519 netbox/dcim/forms/filtersets.py:97
|
||||
#: netbox/dcim/forms/bulk_import.py:604 netbox/dcim/forms/bulk_import.py:1518
|
||||
#: netbox/dcim/forms/bulk_import.py:1552 netbox/dcim/forms/filtersets.py:97
|
||||
#: netbox/dcim/forms/filtersets.py:324 netbox/dcim/forms/filtersets.py:358
|
||||
#: netbox/dcim/forms/filtersets.py:398 netbox/dcim/forms/filtersets.py:449
|
||||
#: netbox/dcim/forms/filtersets.py:739 netbox/dcim/forms/filtersets.py:782
|
||||
@@ -1948,7 +1949,7 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:1007 netbox/dcim/forms/bulk_import.py:1055
|
||||
#: netbox/dcim/forms/bulk_import.py:1072 netbox/dcim/forms/bulk_import.py:1084
|
||||
#: netbox/dcim/forms/bulk_import.py:1132 netbox/dcim/forms/bulk_import.py:1254
|
||||
#: netbox/dcim/forms/bulk_import.py:1590 netbox/dcim/forms/connections.py:24
|
||||
#: netbox/dcim/forms/bulk_import.py:1623 netbox/dcim/forms/connections.py:24
|
||||
#: netbox/dcim/forms/filtersets.py:133 netbox/dcim/forms/filtersets.py:941
|
||||
#: netbox/dcim/forms/filtersets.py:973 netbox/dcim/forms/filtersets.py:1119
|
||||
#: netbox/dcim/forms/filtersets.py:1310 netbox/dcim/forms/filtersets.py:1335
|
||||
@@ -3106,7 +3107,7 @@ msgstr ""
|
||||
#: netbox/templates/tenancy/tenantgroup.html:37
|
||||
#: netbox/templates/virtualization/vminterface.html:39
|
||||
#: netbox/templates/wireless/wirelesslangroup.html:37
|
||||
#: netbox/tenancy/forms/bulk_edit.py:27 netbox/tenancy/forms/bulk_edit.py:62
|
||||
#: netbox/tenancy/forms/bulk_edit.py:27 netbox/tenancy/forms/bulk_edit.py:67
|
||||
#: netbox/tenancy/forms/bulk_import.py:24
|
||||
#: netbox/tenancy/forms/bulk_import.py:58
|
||||
#: netbox/tenancy/forms/model_forms.py:25
|
||||
@@ -4193,8 +4194,8 @@ msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:465 netbox/dcim/forms/bulk_edit.py:972
|
||||
#: netbox/dcim/forms/bulk_import.py:350 netbox/dcim/forms/bulk_import.py:353
|
||||
#: netbox/dcim/forms/bulk_import.py:611 netbox/dcim/forms/bulk_import.py:1526
|
||||
#: netbox/dcim/forms/bulk_import.py:1530 netbox/dcim/forms/filtersets.py:106
|
||||
#: netbox/dcim/forms/bulk_import.py:611 netbox/dcim/forms/bulk_import.py:1559
|
||||
#: netbox/dcim/forms/bulk_import.py:1563 netbox/dcim/forms/filtersets.py:106
|
||||
#: netbox/dcim/forms/filtersets.py:326 netbox/dcim/forms/filtersets.py:407
|
||||
#: netbox/dcim/forms/filtersets.py:421 netbox/dcim/forms/filtersets.py:459
|
||||
#: netbox/dcim/forms/filtersets.py:792 netbox/dcim/forms/filtersets.py:1005
|
||||
@@ -4394,8 +4395,8 @@ msgstr ""
|
||||
msgid "Length"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:875 netbox/dcim/forms/bulk_import.py:1394
|
||||
#: netbox/dcim/forms/bulk_import.py:1397 netbox/dcim/forms/filtersets.py:1140
|
||||
#: netbox/dcim/forms/bulk_edit.py:875 netbox/dcim/forms/bulk_import.py:1408
|
||||
#: netbox/dcim/forms/bulk_import.py:1411 netbox/dcim/forms/filtersets.py:1140
|
||||
msgid "Length unit"
|
||||
msgstr ""
|
||||
|
||||
@@ -4404,17 +4405,17 @@ msgstr ""
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:967 netbox/dcim/forms/bulk_import.py:1513
|
||||
#: netbox/dcim/forms/bulk_edit.py:967 netbox/dcim/forms/bulk_import.py:1546
|
||||
#: netbox/dcim/forms/filtersets.py:1226 netbox/dcim/forms/model_forms.py:855
|
||||
msgid "Power panel"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:989 netbox/dcim/forms/bulk_import.py:1549
|
||||
#: netbox/dcim/forms/bulk_edit.py:989 netbox/dcim/forms/bulk_import.py:1582
|
||||
#: netbox/dcim/forms/filtersets.py:1248 netbox/templates/dcim/powerfeed.html:83
|
||||
msgid "Supply"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:995 netbox/dcim/forms/bulk_import.py:1554
|
||||
#: netbox/dcim/forms/bulk_edit.py:995 netbox/dcim/forms/bulk_import.py:1587
|
||||
#: netbox/dcim/forms/filtersets.py:1253 netbox/templates/dcim/powerfeed.html:95
|
||||
msgid "Phase"
|
||||
msgstr ""
|
||||
@@ -4652,7 +4653,7 @@ msgid "available options"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:137 netbox/dcim/forms/bulk_import.py:601
|
||||
#: netbox/dcim/forms/bulk_import.py:1510 netbox/ipam/forms/bulk_import.py:479
|
||||
#: netbox/dcim/forms/bulk_import.py:1543 netbox/ipam/forms/bulk_import.py:479
|
||||
#: netbox/virtualization/forms/bulk_import.py:64
|
||||
#: netbox/virtualization/forms/bulk_import.py:95
|
||||
msgid "Assigned site"
|
||||
@@ -4715,7 +4716,7 @@ msgstr ""
|
||||
msgid "Parent site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:347 netbox/dcim/forms/bulk_import.py:1523
|
||||
#: netbox/dcim/forms/bulk_import.py:347 netbox/dcim/forms/bulk_import.py:1556
|
||||
msgid "Rack's location (if any)"
|
||||
msgstr ""
|
||||
|
||||
@@ -4766,7 +4767,7 @@ msgstr ""
|
||||
msgid "Limit platform assignments to this manufacturer"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:534 netbox/dcim/forms/bulk_import.py:1593
|
||||
#: netbox/dcim/forms/bulk_import.py:534 netbox/dcim/forms/bulk_import.py:1626
|
||||
#: netbox/tenancy/forms/bulk_import.py:105
|
||||
msgid "Assigned role"
|
||||
msgstr ""
|
||||
@@ -4956,7 +4957,7 @@ msgid "Corresponding rear port"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1020 netbox/dcim/forms/bulk_import.py:1061
|
||||
#: netbox/dcim/forms/bulk_import.py:1384
|
||||
#: netbox/dcim/forms/bulk_import.py:1398
|
||||
msgid "Physical medium classification"
|
||||
msgstr ""
|
||||
|
||||
@@ -5045,102 +5046,120 @@ msgid "Must specify the parent device or VM when assigning an interface"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1339
|
||||
msgid "Side A site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1343
|
||||
#: netbox/wireless/forms/bulk_import.py:94
|
||||
msgid "Site of parent device A (if any)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1346
|
||||
msgid "Side A device"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1342 netbox/dcim/forms/bulk_import.py:1360
|
||||
#: netbox/dcim/forms/bulk_import.py:1349 netbox/dcim/forms/bulk_import.py:1374
|
||||
msgid "Device name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1345
|
||||
#: netbox/dcim/forms/bulk_import.py:1352
|
||||
msgid "Side A type"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1351
|
||||
#: netbox/dcim/forms/bulk_import.py:1358
|
||||
msgid "Side A name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1352 netbox/dcim/forms/bulk_import.py:1370
|
||||
#: netbox/dcim/forms/bulk_import.py:1359 netbox/dcim/forms/bulk_import.py:1384
|
||||
msgid "Termination name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1357
|
||||
#: netbox/dcim/forms/bulk_import.py:1364
|
||||
msgid "Side B site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1368
|
||||
#: netbox/wireless/forms/bulk_import.py:115
|
||||
msgid "Site of parent device B (if any)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1371
|
||||
msgid "Side B device"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1363
|
||||
#: netbox/dcim/forms/bulk_import.py:1377
|
||||
msgid "Side B type"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1369
|
||||
#: netbox/dcim/forms/bulk_import.py:1383
|
||||
msgid "Side B name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1378
|
||||
#: netbox/dcim/forms/bulk_import.py:1392
|
||||
#: netbox/wireless/forms/bulk_import.py:134
|
||||
msgid "Connection status"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1430
|
||||
#: netbox/dcim/forms/bulk_import.py:1463
|
||||
#, python-brace-format
|
||||
msgid "Side {side_upper}: {device} {termination_object} is already connected"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1436
|
||||
#: netbox/dcim/forms/bulk_import.py:1469
|
||||
#, python-brace-format
|
||||
msgid "{side_upper} side termination not found: {device} {name}"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1461 netbox/dcim/forms/model_forms.py:891
|
||||
#: netbox/dcim/forms/bulk_import.py:1494 netbox/dcim/forms/model_forms.py:891
|
||||
#: netbox/dcim/tables/devices.py:1069 netbox/templates/dcim/device.html:138
|
||||
#: netbox/templates/dcim/virtualchassis.html:27
|
||||
#: netbox/templates/dcim/virtualchassis.html:67
|
||||
msgid "Master"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1465
|
||||
#: netbox/dcim/forms/bulk_import.py:1498
|
||||
msgid "Master device"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1482
|
||||
#: netbox/dcim/forms/bulk_import.py:1515
|
||||
msgid "Name of parent site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1516
|
||||
#: netbox/dcim/forms/bulk_import.py:1549
|
||||
msgid "Upstream power panel"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1546
|
||||
#: netbox/dcim/forms/bulk_import.py:1579
|
||||
msgid "Primary or redundant"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1551
|
||||
#: netbox/dcim/forms/bulk_import.py:1584
|
||||
msgid "Supply type (AC/DC)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1556
|
||||
#: netbox/dcim/forms/bulk_import.py:1589
|
||||
msgid "Single or three-phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1607 netbox/dcim/forms/model_forms.py:1847
|
||||
#: netbox/dcim/forms/bulk_import.py:1640 netbox/dcim/forms/model_forms.py:1847
|
||||
#: netbox/templates/dcim/device.html:196
|
||||
#: netbox/templates/dcim/virtualdevicecontext.html:30
|
||||
#: netbox/templates/virtualization/virtualmachine.html:52
|
||||
msgid "Primary IPv4"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1611
|
||||
#: netbox/dcim/forms/bulk_import.py:1644
|
||||
msgid "IPv4 address with mask, e.g. 1.2.3.4/24"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1614 netbox/dcim/forms/model_forms.py:1856
|
||||
#: netbox/dcim/forms/bulk_import.py:1647 netbox/dcim/forms/model_forms.py:1856
|
||||
#: netbox/templates/dcim/device.html:212
|
||||
#: netbox/templates/dcim/virtualdevicecontext.html:41
|
||||
#: netbox/templates/virtualization/virtualmachine.html:68
|
||||
msgid "Primary IPv6"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1618
|
||||
#: netbox/dcim/forms/bulk_import.py:1651
|
||||
msgid "IPv6 address with prefix length, e.g. 2001:db8::1/64"
|
||||
msgstr ""
|
||||
|
||||
@@ -7784,7 +7803,7 @@ msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/extras/choices.py:108 netbox/templates/tenancy/contact.html:67
|
||||
#: netbox/tenancy/forms/bulk_edit.py:125
|
||||
#: netbox/tenancy/forms/bulk_edit.py:130
|
||||
#: netbox/wireless/forms/model_forms.py:173
|
||||
msgid "Link"
|
||||
msgstr ""
|
||||
@@ -8325,7 +8344,7 @@ msgstr ""
|
||||
#: netbox/netbox/navigation/menu.py:433
|
||||
#: netbox/templates/extras/notificationgroup.html:31
|
||||
#: netbox/templates/tenancy/contact.html:21
|
||||
#: netbox/tenancy/forms/bulk_edit.py:139 netbox/tenancy/forms/filtersets.py:78
|
||||
#: netbox/tenancy/forms/bulk_edit.py:144 netbox/tenancy/forms/filtersets.py:78
|
||||
#: netbox/tenancy/forms/model_forms.py:99 netbox/tenancy/tables/contacts.py:68
|
||||
#: netbox/users/forms/model_forms.py:182 netbox/users/forms/model_forms.py:194
|
||||
#: netbox/users/forms/model_forms.py:306 netbox/users/tables.py:35
|
||||
@@ -9855,7 +9874,7 @@ msgstr ""
|
||||
#: netbox/ipam/filtersets.py:466 netbox/ipam/filtersets.py:470
|
||||
#: netbox/ipam/filtersets.py:562 netbox/ipam/forms/model_forms.py:506
|
||||
#: netbox/templates/tenancy/contact.html:63
|
||||
#: netbox/tenancy/forms/bulk_edit.py:120
|
||||
#: netbox/tenancy/forms/bulk_edit.py:125
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
@@ -12311,7 +12330,7 @@ msgstr ""
|
||||
|
||||
#: netbox/templates/account/profile.html:27
|
||||
#: netbox/templates/tenancy/contact.html:53 netbox/templates/users/user.html:23
|
||||
#: netbox/tenancy/forms/bulk_edit.py:116
|
||||
#: netbox/tenancy/forms/bulk_edit.py:121
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
@@ -14826,7 +14845,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: netbox/templates/tenancy/contact.html:18 netbox/tenancy/filtersets.py:152
|
||||
#: netbox/tenancy/forms/bulk_edit.py:149 netbox/tenancy/forms/filtersets.py:102
|
||||
#: netbox/tenancy/forms/bulk_edit.py:154 netbox/tenancy/forms/filtersets.py:102
|
||||
#: netbox/tenancy/forms/forms.py:57 netbox/tenancy/forms/model_forms.py:108
|
||||
#: netbox/tenancy/forms/model_forms.py:132
|
||||
#: netbox/tenancy/tables/contacts.py:106
|
||||
@@ -14834,12 +14853,12 @@ msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/templates/tenancy/contact.html:39
|
||||
#: netbox/tenancy/forms/bulk_edit.py:106
|
||||
#: netbox/tenancy/forms/bulk_edit.py:111
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/templates/tenancy/contact.html:43
|
||||
#: netbox/tenancy/forms/bulk_edit.py:111 netbox/tenancy/tables/contacts.py:72
|
||||
#: netbox/tenancy/forms/bulk_edit.py:116 netbox/tenancy/tables/contacts.py:72
|
||||
msgid "Phone"
|
||||
msgstr ""
|
||||
|
||||
@@ -15208,15 +15227,15 @@ msgstr ""
|
||||
msgid "Tenant Group (slug)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/tenancy/forms/bulk_edit.py:67
|
||||
#: netbox/tenancy/forms/bulk_edit.py:72
|
||||
msgid "Desciption"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/tenancy/forms/bulk_edit.py:96
|
||||
#: netbox/tenancy/forms/bulk_edit.py:101
|
||||
msgid "Add groups"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/tenancy/forms/bulk_edit.py:101
|
||||
#: netbox/tenancy/forms/bulk_edit.py:106
|
||||
msgid "Remove groups"
|
||||
msgstr ""
|
||||
|
||||
@@ -16673,10 +16692,6 @@ msgstr ""
|
||||
msgid "Bridged VLAN"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/wireless/forms/bulk_import.py:94
|
||||
msgid "Site of parent device A (if any)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/wireless/forms/bulk_import.py:100
|
||||
msgid "Parent device of assigned interface A"
|
||||
msgstr ""
|
||||
@@ -16690,10 +16705,6 @@ msgstr ""
|
||||
msgid "Assigned interface A"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/wireless/forms/bulk_import.py:115
|
||||
msgid "Site of parent device B (if any)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/wireless/forms/bulk_import.py:121
|
||||
msgid "Parent device of assigned interface B"
|
||||
msgstr ""
|
||||
|
||||
@@ -13,6 +13,8 @@ FILTER_CHAR_BASED_LOOKUP_MAP = dict(
|
||||
ie='iexact',
|
||||
nie='iexact',
|
||||
empty='empty',
|
||||
regex='regex',
|
||||
iregex='iregex',
|
||||
)
|
||||
|
||||
FILTER_NUMERIC_BASED_LOOKUP_MAP = dict(
|
||||
|
||||
@@ -180,6 +180,10 @@ class BaseFilterSetTest(TestCase):
|
||||
self.assertEqual(self.filters['charfield__niew'].exclude, True)
|
||||
self.assertEqual(self.filters['charfield__empty'].lookup_expr, 'empty')
|
||||
self.assertEqual(self.filters['charfield__empty'].exclude, False)
|
||||
self.assertEqual(self.filters['charfield__regex'].lookup_expr, 'regex')
|
||||
self.assertEqual(self.filters['charfield__regex'].exclude, False)
|
||||
self.assertEqual(self.filters['charfield__iregex'].lookup_expr, 'iregex')
|
||||
self.assertEqual(self.filters['charfield__iregex'].exclude, False)
|
||||
|
||||
def test_number_filter(self):
|
||||
self.assertIsInstance(self.filters['numberfield'], django_filters.NumberFilter)
|
||||
@@ -220,6 +224,10 @@ class BaseFilterSetTest(TestCase):
|
||||
self.assertEqual(self.filters['macaddressfield__iew'].exclude, False)
|
||||
self.assertEqual(self.filters['macaddressfield__niew'].lookup_expr, 'iendswith')
|
||||
self.assertEqual(self.filters['macaddressfield__niew'].exclude, True)
|
||||
self.assertEqual(self.filters['macaddressfield__regex'].lookup_expr, 'regex')
|
||||
self.assertEqual(self.filters['macaddressfield__regex'].exclude, False)
|
||||
self.assertEqual(self.filters['macaddressfield__iregex'].lookup_expr, 'iregex')
|
||||
self.assertEqual(self.filters['macaddressfield__iregex'].exclude, False)
|
||||
|
||||
def test_model_choice_filter(self):
|
||||
self.assertIsInstance(self.filters['modelchoicefield'], django_filters.ModelChoiceFilter)
|
||||
@@ -257,6 +265,10 @@ class BaseFilterSetTest(TestCase):
|
||||
self.assertEqual(self.filters['multivaluecharfield__iew'].exclude, False)
|
||||
self.assertEqual(self.filters['multivaluecharfield__niew'].lookup_expr, 'iendswith')
|
||||
self.assertEqual(self.filters['multivaluecharfield__niew'].exclude, True)
|
||||
self.assertEqual(self.filters['multivaluecharfield__regex'].lookup_expr, 'regex')
|
||||
self.assertEqual(self.filters['multivaluecharfield__regex'].exclude, False)
|
||||
self.assertEqual(self.filters['multivaluecharfield__iregex'].lookup_expr, 'iregex')
|
||||
self.assertEqual(self.filters['multivaluecharfield__iregex'].exclude, False)
|
||||
|
||||
def test_multi_value_date_filter(self):
|
||||
self.assertIsInstance(self.filters['datefield'], MultiValueDateFilter)
|
||||
@@ -340,6 +352,10 @@ class BaseFilterSetTest(TestCase):
|
||||
self.assertEqual(self.filters['multiplechoicefield__iew'].exclude, False)
|
||||
self.assertEqual(self.filters['multiplechoicefield__niew'].lookup_expr, 'iendswith')
|
||||
self.assertEqual(self.filters['multiplechoicefield__niew'].exclude, True)
|
||||
self.assertEqual(self.filters['multiplechoicefield__regex'].lookup_expr, 'regex')
|
||||
self.assertEqual(self.filters['multiplechoicefield__regex'].exclude, False)
|
||||
self.assertEqual(self.filters['multiplechoicefield__iregex'].lookup_expr, 'iregex')
|
||||
self.assertEqual(self.filters['multiplechoicefield__iregex'].exclude, False)
|
||||
|
||||
def test_tag_filter(self):
|
||||
self.assertIsInstance(self.filters['tagfield'], TagFilter)
|
||||
@@ -534,6 +550,14 @@ class DynamicFilterLookupExpressionTest(TestCase):
|
||||
params = {'slug__niew': ['-1']}
|
||||
self.assertEqual(SiteFilterSet(params, Site.objects.all()).qs.count(), 2)
|
||||
|
||||
def test_site_slug_regex(self):
|
||||
params = {'slug__regex': ['^def-[a-z]*-2$']}
|
||||
self.assertEqual(SiteFilterSet(params, Site.objects.all()).qs.count(), 1)
|
||||
|
||||
def test_site_slug_iregex(self):
|
||||
params = {'slug__iregex': ['^DEF-[a-z]*-2$']}
|
||||
self.assertEqual(SiteFilterSet(params, Site.objects.all()).qs.count(), 1)
|
||||
|
||||
def test_provider_asn_lt(self):
|
||||
params = {'asn__lt': [65101]}
|
||||
self.assertEqual(ASNFilterSet(params, ASN.objects.all()).qs.count(), 1)
|
||||
@@ -618,6 +642,14 @@ class DynamicFilterLookupExpressionTest(TestCase):
|
||||
params = {'mac_address__nic': ['aa:', 'bb']}
|
||||
self.assertEqual(DeviceFilterSet(params, Device.objects.all()).qs.count(), 1)
|
||||
|
||||
def test_device_mac_address_regex(self):
|
||||
params = {'mac_address__regex': ['^cc.*:03$']}
|
||||
self.assertEqual(DeviceFilterSet(params, Device.objects.all()).qs.count(), 1)
|
||||
|
||||
def test_device_mac_address_iregex(self):
|
||||
params = {'mac_address__iregex': ['^CC.*:03$']}
|
||||
self.assertEqual(DeviceFilterSet(params, Device.objects.all()).qs.count(), 1)
|
||||
|
||||
def test_interface_rf_role_empty(self):
|
||||
params = {'rf_role__empty': 'true'}
|
||||
self.assertEqual(InterfaceFilterSet(params, Interface.objects.all()).qs.count(), 5)
|
||||
|
||||
Reference in New Issue
Block a user