mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-09 13:22:18 -06:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5fc37282f | ||
|
|
525ed359cd | ||
|
|
fe00db62d6 | ||
|
|
bcfa760cf9 | ||
|
|
613e8f05c2 | ||
|
|
59f8f0c7ea | ||
|
|
ae0c8deec2 | ||
|
|
b508415983 | ||
|
|
a98d014763 | ||
|
|
51e5e49d3b | ||
|
|
0eced489da | ||
|
|
5138d12942 | ||
|
|
fe30276db2 | ||
|
|
e51e8b5c8a | ||
|
|
170900e80f | ||
|
|
6726403de9 | ||
|
|
f6d18d243e | ||
|
|
8bd9b258a8 | ||
|
|
0256448dd8 | ||
|
|
dc70fdbe03 | ||
|
|
ce1a2875bc | ||
|
|
b4c9ec27e0 | ||
|
|
8977ded7b6 | ||
|
|
afb4c636fe | ||
|
|
ff40a13f29 | ||
|
|
61a48320af | ||
|
|
d53249060d | ||
|
|
22eebbbc71 | ||
|
|
4227c6b806 | ||
|
|
14695037da | ||
|
|
0d717cdc82 | ||
|
|
ae8c5ae7b8 | ||
|
|
fb0ed3db2f | ||
|
|
c69fad7429 | ||
|
|
92a2f529e3 | ||
|
|
bd74e2f30b | ||
|
|
a950c95416 | ||
|
|
dc9e9fd08f | ||
|
|
1abbaf99dc | ||
|
|
af6bb53a01 | ||
|
|
2d7e5a57e7 | ||
|
|
b6737aff59 | ||
|
|
c5f2cbf9fa | ||
|
|
d6d8b078b9 | ||
|
|
1d7a7e2d1d | ||
|
|
4a290f3834 | ||
|
|
9e492cbb4d | ||
|
|
e17d79e10f | ||
|
|
28a2981a4f | ||
|
|
d356e288a2 | ||
|
|
dd5f37391f | ||
|
|
17d6584ef4 | ||
|
|
ad4fb3ce8b | ||
|
|
5f1f8ee73b | ||
|
|
60224be272 | ||
|
|
6dcd48fef1 | ||
|
|
951e7a68e9 | ||
|
|
86bafbb760 | ||
|
|
a6564c49e2 | ||
|
|
c89735cd4e | ||
|
|
f3216abebf | ||
|
|
5676bd15dd | ||
|
|
bf8d57c7d1 | ||
|
|
0d415d94a5 | ||
|
|
73a1d6a7ba | ||
|
|
72d5c6fd1b | ||
|
|
6d5d9c8af3 | ||
|
|
c27cea981c | ||
|
|
f7f6704fc1 | ||
|
|
fca97f9768 | ||
|
|
7a5a73ce34 | ||
|
|
170e01b549 | ||
|
|
99dc46a89e | ||
|
|
848aa0b098 | ||
|
|
81a0889568 | ||
|
|
0a820d9c98 | ||
|
|
209a9f0ffc | ||
|
|
3101a86381 | ||
|
|
27ca0d0930 | ||
|
|
6ca045e1a9 | ||
|
|
0c86693dc4 | ||
|
|
5285b6926f | ||
|
|
f3cfc17a52 | ||
|
|
c58166137c | ||
|
|
28a02e9943 | ||
|
|
c6d9206dd1 | ||
|
|
d144d3a584 | ||
|
|
f499f2dd66 |
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -17,15 +17,20 @@ about: Report a reproducible bug in the current release of NetBox
|
||||
-->
|
||||
### Environment
|
||||
* Python version: <!-- Example: 3.5.4 -->
|
||||
* NetBox version: <!-- Example: 2.3.6 -->
|
||||
* NetBox version: <!-- Example: 2.5.2 -->
|
||||
|
||||
<!--
|
||||
Describe in detail the steps that someone else can take to reproduce this
|
||||
bug using the current stable release of NetBox (or the current beta release
|
||||
where applicable).
|
||||
Describe in detail the exact steps that someone else can take to reproduce
|
||||
this bug using the current stable release of NetBox (or the current beta
|
||||
release where applicable). Begin with the creation of any necessary
|
||||
database objects and call out every operation being performed explicitly.
|
||||
If reporting a bug in the REST API, be sure to reconstruct the raw HTTP
|
||||
request(s) being made: Don't rely on a wrapper like pynetbox.
|
||||
-->
|
||||
### Steps to Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
<!-- What did you expect to happen? -->
|
||||
### Expected Behavior
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@
|
||||
fabfile.py
|
||||
*.swp
|
||||
gunicorn_config.py
|
||||
.DS_Store
|
||||
.vscode
|
||||
|
||||
65
CHANGELOG.md
65
CHANGELOG.md
@@ -1,3 +1,68 @@
|
||||
v2.5.5 (2019-01-31)
|
||||
|
||||
## Enhancements
|
||||
|
||||
* [#2805](https://github.com/digitalocean/netbox/issues/2805) - Allow null route distinguisher for VRFs
|
||||
* [#2809](https://github.com/digitalocean/netbox/issues/2809) - Remove VRF child prefixes table; link to main prefixes view
|
||||
* [#2825](https://github.com/digitalocean/netbox/issues/2825) - Include directly connected device for front/rear ports
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* [#2824](https://github.com/digitalocean/netbox/issues/2824) - Fix template exception when viewing rack elevations list
|
||||
* [#2833](https://github.com/digitalocean/netbox/issues/2833) - Fix form widget for front port template creation
|
||||
* [#2835](https://github.com/digitalocean/netbox/issues/2835) - Fix certain model filters did not support the `q` query param
|
||||
* [#2837](https://github.com/digitalocean/netbox/issues/2837) - Fix select2 nullable filter fields add multiple null_option elements when paging
|
||||
|
||||
---
|
||||
|
||||
v2.5.4 (2019-01-29)
|
||||
|
||||
## Enhancements
|
||||
|
||||
* [#2516](https://github.com/digitalocean/netbox/issues/2516) - Implemented Select2 for all Model backed selection fields
|
||||
* [#2590](https://github.com/digitalocean/netbox/issues/2590) - Implemented the color picker with Select2 to show colors in the background
|
||||
* [#2733](https://github.com/digitalocean/netbox/issues/2733) - Enable bulk assignment of MAC addresses to interfaces
|
||||
* [#2735](https://github.com/digitalocean/netbox/issues/2735) - Implemented Select2 for all list filter form select elements
|
||||
* [#2753](https://github.com/digitalocean/netbox/issues/2753) - Implemented Select2 to replace most all instances of select fields in forms
|
||||
* [#2766](https://github.com/digitalocean/netbox/issues/2766) - Extend users admin table to include superuser and active fields
|
||||
* [#2782](https://github.com/digitalocean/netbox/issues/2782) - Add `is_pool` field for prefix filtering
|
||||
* [#2807](https://github.com/digitalocean/netbox/issues/2807) - Include device site/rack assignment in cable trace view
|
||||
* [#2808](https://github.com/digitalocean/netbox/issues/2808) - Loosen version pinning for Django to allow patch releases
|
||||
* [#2810](https://github.com/digitalocean/netbox/issues/2810) - Include description fields in interface connections export
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* [#2779](https://github.com/digitalocean/netbox/issues/2779) - Include "none" option when filter IP addresses by role
|
||||
* [#2783](https://github.com/digitalocean/netbox/issues/2783) - Fix AttributeError exception when attempting to delete region(s)
|
||||
* [#2795](https://github.com/digitalocean/netbox/issues/2795) - Fix duplicate display of pagination controls on child prefix/IP tables
|
||||
* [#2798](https://github.com/digitalocean/netbox/issues/2798) - Properly URL-encode "map it" link on site view
|
||||
* [#2802](https://github.com/digitalocean/netbox/issues/2802) - Better error handling for unsupported NAPALM methods
|
||||
* [#2816](https://github.com/digitalocean/netbox/issues/2816) - Handle exception when deleting a device with connected components
|
||||
|
||||
---
|
||||
|
||||
v2.5.3 (2019-01-11)
|
||||
|
||||
## Enhancements
|
||||
|
||||
* [#1630](https://github.com/digitalocean/netbox/issues/1630) - Enable bulk editing of prefix/IP mask length
|
||||
* [#1870](https://github.com/digitalocean/netbox/issues/1870) - Add per-page toggle to object lists
|
||||
* [#1871](https://github.com/digitalocean/netbox/issues/1871) - Enable filtering sites by parent region
|
||||
* [#1983](https://github.com/digitalocean/netbox/issues/1983) - Enable regular expressions when bulk renaming device components
|
||||
* [#2682](https://github.com/digitalocean/netbox/issues/2682) - Add DAC and AOC cable types
|
||||
* [#2693](https://github.com/digitalocean/netbox/issues/2693) - Additional cable colors
|
||||
* [#2726](https://github.com/digitalocean/netbox/issues/2726) - Include cables in global search
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* [#2742](https://github.com/digitalocean/netbox/issues/2742) - Preserve cluster assignment when editing a device
|
||||
* [#2757](https://github.com/digitalocean/netbox/issues/2757) - Always treat first/last IPs within a /31 or /127 as usable
|
||||
* [#2762](https://github.com/digitalocean/netbox/issues/2762) - Add missing DCIM field values to API `_choices` endpoint
|
||||
* [#2777](https://github.com/digitalocean/netbox/issues/2777) - Fix cable validation to handle duplicate connections on import
|
||||
|
||||
|
||||
---
|
||||
|
||||
v2.5.2 (2018-12-21)
|
||||
|
||||
## Enhancements
|
||||
|
||||
@@ -37,7 +37,7 @@ and run `upgrade.sh`.
|
||||
|
||||
## Alternative Installations
|
||||
|
||||
* [Docker container](https://github.com/ninech/netbox-docker) (via [@cimnine](https://github.com/cimnine))
|
||||
* [Docker container](https://github.com/netbox-community/netbox-docker) (via [@cimnine](https://github.com/cimnine))
|
||||
* [Vagrant deployment](https://github.com/ryanmerolle/netbox-vagrant) (via [@ryanmerolle](https://github.com/ryanmerolle))
|
||||
* [Ansible deployment](https://github.com/lae/ansible-role-netbox) (via [@lae](https://github.com/lae))
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Tags
|
||||
|
||||
Tags are free-form text labels which can be applied to a variety of objects within NetBox. Tags are created on-demand as they are assigned to objects. Use commas to separate tags when adding multiple tags to an object 9for example: `Inventoried, Monitored`). Use double quotes around a multi-word tag when adding only one tag, e.g. `"Core Switch"`.
|
||||
Tags are free-form text labels which can be applied to a variety of objects within NetBox. Tags are created on-demand as they are assigned to objects. Use commas to separate tags when adding multiple tags to an object (for example: `Inventoried, Monitored`). Use double quotes around a multi-word tag when adding only one tag, e.g. `"Core Switch"`.
|
||||
|
||||
Each tag has a label and a URL-friendly slug. For example, the slug for a tag named "Dunder Mifflin, Inc." would be `dunder-mifflin-inc`. The slug is generated automatically and makes tags easier to work with as URL parameters.
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ The time zone NetBox will use when dealing with dates and times. It is recommend
|
||||
|
||||
Default: False
|
||||
|
||||
Enable this option to run the webhook backend. See the docs section on the webhook backend [here](../miscellaneous/webhooks/) for more information on setup and use.
|
||||
Enable this option to run the webhook backend. See the docs section on the webhook backend [here](../additional-features/webhooks/) for more information on setup and use.
|
||||
|
||||
---
|
||||
|
||||
@@ -274,7 +274,7 @@ SHORT_DATETIME_FORMAT = 'Y-m-d H:i' # 2016-06-27 13:23
|
||||
|
||||
## Redis Connection Settings
|
||||
|
||||
[Redis](https://redis.io/) is a key-value store which functions as a very lightweight database. It is required when enabling NetBox [webhooks](../miscellaneous/webhooks/). A Redis connection is configured using a dictionary similar to the following:
|
||||
[Redis](https://redis.io/) is a key-value store which functions as a very lightweight database. It is required when enabling NetBox [webhooks](../additional-features/webhooks/). A Redis connection is configured using a dictionary similar to the following:
|
||||
|
||||
```
|
||||
REDIS = {
|
||||
|
||||
@@ -83,7 +83,7 @@ An IP address can be designated as the network address translation (NAT) inside
|
||||
|
||||
A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space).
|
||||
|
||||
Each VRF is assigned a unique name and route distinguisher (RD). The RD is expected to take one of the forms prescribed in [RFC 4364](https://tools.ietf.org/html/rfc4364#section-4.2), however its formatting is not strictly enforced.
|
||||
Each VRF is assigned a unique name and an optional route distinguisher (RD). The RD is expected to take one of the forms prescribed in [RFC 4364](https://tools.ietf.org/html/rfc4364#section-4.2), however its formatting is not strictly enforced.
|
||||
|
||||
Each prefix and IP address may be assigned to one (and only one) VRF. If you have a prefix or IP address which exists in multiple VRFs, you will need to create a separate instance of it in NetBox for each VRF. Any IP prefix or address not assigned to a VRF is said to belong to the "global" table.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.db.models import Q
|
||||
from dcim.models import Site
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NumericInFilter, TagFilter
|
||||
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
||||
from .constants import CIRCUIT_STATUS_CHOICES
|
||||
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
||||
|
||||
@@ -47,7 +47,7 @@ class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
)
|
||||
|
||||
|
||||
class CircuitTypeFilter(django_filters.FilterSet):
|
||||
class CircuitTypeFilter(NameSlugSearchFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = CircuitType
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site
|
||||
@@ -7,8 +6,8 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
||||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
AnnotatedMultipleChoiceField, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, FilterChoiceField,
|
||||
SmallTextarea, SlugField,
|
||||
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
|
||||
FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
|
||||
)
|
||||
from .constants import CIRCUIT_STATUS_CHOICES
|
||||
from .models import Circuit, CircuitTermination, CircuitType, Provider
|
||||
@@ -107,7 +106,11 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug'
|
||||
to_field_name='slug',
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
asn = forms.IntegerField(
|
||||
required=False,
|
||||
@@ -161,6 +164,16 @@ class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
'install_date': "Format: YYYY-MM-DD",
|
||||
'commit_rate': "Committed rate",
|
||||
}
|
||||
widgets = {
|
||||
'provider': APISelect(
|
||||
api_url="/api/circuits/providers/"
|
||||
),
|
||||
'type': APISelect(
|
||||
api_url="/api/circuits/circuit-types/"
|
||||
),
|
||||
'status': StaticSelect2(),
|
||||
|
||||
}
|
||||
|
||||
|
||||
class CircuitCSVForm(forms.ModelForm):
|
||||
@@ -209,20 +222,30 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
|
||||
)
|
||||
type = forms.ModelChoiceField(
|
||||
queryset=CircuitType.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/circuits/circuit-types/"
|
||||
)
|
||||
)
|
||||
provider = forms.ModelChoiceField(
|
||||
queryset=Provider.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/circuits/providers/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
|
||||
required=False,
|
||||
initial=''
|
||||
initial='',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
commit_rate = forms.IntegerField(
|
||||
required=False,
|
||||
@@ -249,35 +272,43 @@ class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
label='Search'
|
||||
)
|
||||
type = FilterChoiceField(
|
||||
queryset=CircuitType.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=CircuitType.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/circuits/circuit-types/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
provider = FilterChoiceField(
|
||||
queryset=Provider.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=Provider.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/circuits/providers/",
|
||||
value_field="slug",
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=CIRCUIT_STATUS_CHOICES,
|
||||
annotate=Circuit.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('circuit_terminations')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
commit_rate = forms.IntegerField(
|
||||
required=False,
|
||||
@@ -304,4 +335,7 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
|
||||
}
|
||||
widgets = {
|
||||
'term_side': forms.HiddenInput(),
|
||||
'site': APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ from django.db import models
|
||||
from django.urls import reverse
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from dcim.constants import CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_CONNECTED, STATUS_CLASSES
|
||||
from dcim.constants import CONNECTION_STATUS_CHOICES, STATUS_CLASSES
|
||||
from dcim.fields import ASNField
|
||||
from dcim.models import CableTermination
|
||||
from extras.models import CustomFieldModel, ObjectChange
|
||||
@@ -283,6 +283,10 @@ class CircuitTermination(CableTermination):
|
||||
object_data=serialize_object(self)
|
||||
).save()
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self.circuit
|
||||
|
||||
def get_peer_termination(self):
|
||||
peer_side = 'Z' if self.term_side == 'A' else 'A'
|
||||
try:
|
||||
|
||||
@@ -35,13 +35,18 @@ from .exceptions import MissingFilterException
|
||||
|
||||
class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
|
||||
fields = (
|
||||
(Cable, ['length_unit']),
|
||||
(Device, ['face', 'status']),
|
||||
(Cable, ['length_unit', 'status', 'type']),
|
||||
(ConsolePort, ['connection_status']),
|
||||
(Interface, ['connection_status', 'form_factor', 'mode']),
|
||||
(Device, ['face', 'status']),
|
||||
(DeviceType, ['subdevice_role']),
|
||||
(FrontPort, ['type']),
|
||||
(FrontPortTemplate, ['type']),
|
||||
(Interface, ['form_factor', 'mode']),
|
||||
(InterfaceTemplate, ['form_factor']),
|
||||
(PowerPort, ['connection_status']),
|
||||
(Rack, ['outer_unit', 'status', 'type', 'width']),
|
||||
(RearPort, ['type']),
|
||||
(RearPortTemplate, ['type']),
|
||||
(Site, ['status']),
|
||||
)
|
||||
|
||||
|
||||
@@ -339,11 +339,14 @@ CABLE_TYPE_CAT5E = 1510
|
||||
CABLE_TYPE_CAT6 = 1600
|
||||
CABLE_TYPE_CAT6A = 1610
|
||||
CABLE_TYPE_CAT7 = 1700
|
||||
CABLE_TYPE_DAC_ACTIVE = 1800
|
||||
CABLE_TYPE_DAC_PASSIVE = 1810
|
||||
CABLE_TYPE_MMF_OM1 = 3010
|
||||
CABLE_TYPE_MMF_OM2 = 3020
|
||||
CABLE_TYPE_MMF_OM3 = 3030
|
||||
CABLE_TYPE_MMF_OM4 = 3040
|
||||
CABLE_TYPE_SMF = 3500
|
||||
CABLE_TYPE_AOC = 3800
|
||||
CABLE_TYPE_POWER = 5000
|
||||
CABLE_TYPE_CHOICES = (
|
||||
(
|
||||
@@ -354,6 +357,8 @@ CABLE_TYPE_CHOICES = (
|
||||
(CABLE_TYPE_CAT6, 'CAT6'),
|
||||
(CABLE_TYPE_CAT6A, 'CAT6a'),
|
||||
(CABLE_TYPE_CAT7, 'CAT7'),
|
||||
(CABLE_TYPE_DAC_ACTIVE, 'Direct Attach Copper (Active)'),
|
||||
(CABLE_TYPE_DAC_PASSIVE, 'Direct Attach Copper (Passive)'),
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -363,6 +368,7 @@ CABLE_TYPE_CHOICES = (
|
||||
(CABLE_TYPE_MMF_OM3, 'Multimode Fiber (OM3)'),
|
||||
(CABLE_TYPE_MMF_OM4, 'Multimode Fiber (OM4)'),
|
||||
(CABLE_TYPE_SMF, 'Singlemode Fiber'),
|
||||
(CABLE_TYPE_AOC, 'Active Optical Cabling (AOC)'),
|
||||
),
|
||||
),
|
||||
(CABLE_TYPE_POWER, 'Power'),
|
||||
|
||||
@@ -8,7 +8,7 @@ from netaddr.core import AddrFormatError
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.constants import COLOR_CHOICES
|
||||
from utilities.filters import NullableCharFieldFilter, NumericInFilter, TagFilter
|
||||
from utilities.filters import NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter
|
||||
from virtualization.models import Cluster
|
||||
from .constants import *
|
||||
from .models import (
|
||||
@@ -19,11 +19,7 @@ from .models import (
|
||||
)
|
||||
|
||||
|
||||
class RegionFilter(django_filters.FilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
class RegionFilter(NameSlugSearchFilterSet):
|
||||
parent_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
label='Parent region (ID)',
|
||||
@@ -39,15 +35,6 @@ class RegionFilter(django_filters.FilterSet):
|
||||
model = Region
|
||||
fields = ['name', 'slug']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = (
|
||||
Q(name__icontains=value) |
|
||||
Q(slug__icontains=value)
|
||||
)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
id__in = NumericInFilter(
|
||||
@@ -62,14 +49,14 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
choices=SITE_STATUS_CHOICES,
|
||||
null_value=None
|
||||
)
|
||||
region_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
region_id = django_filters.NumberFilter(
|
||||
method='filter_region',
|
||||
field_name='pk',
|
||||
label='Region (ID)',
|
||||
)
|
||||
region = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='region__slug',
|
||||
queryset=Region.objects.all(),
|
||||
to_field_name='slug',
|
||||
region = django_filters.CharFilter(
|
||||
method='filter_region',
|
||||
field_name='slug',
|
||||
label='Region (slug)',
|
||||
)
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
@@ -108,12 +95,18 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
pass
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class RackGroupFilter(django_filters.FilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
def filter_region(self, queryset, name, value):
|
||||
try:
|
||||
region = Region.objects.get(**{name: value})
|
||||
except ObjectDoesNotExist:
|
||||
return queryset.none()
|
||||
return queryset.filter(
|
||||
Q(region=region) |
|
||||
Q(region__in=region.get_descendants())
|
||||
)
|
||||
|
||||
|
||||
class RackGroupFilter(NameSlugSearchFilterSet):
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
@@ -129,17 +122,8 @@ class RackGroupFilter(django_filters.FilterSet):
|
||||
model = RackGroup
|
||||
fields = ['site_id', 'name', 'slug']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = (
|
||||
Q(name__icontains=value) |
|
||||
Q(slug__icontains=value)
|
||||
)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class RackRoleFilter(django_filters.FilterSet):
|
||||
class RackRoleFilter(NameSlugSearchFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = RackRole
|
||||
@@ -293,7 +277,7 @@ class RackReservationFilter(django_filters.FilterSet):
|
||||
)
|
||||
|
||||
|
||||
class ManufacturerFilter(django_filters.FilterSet):
|
||||
class ManufacturerFilter(NameSlugSearchFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = Manufacturer
|
||||
@@ -383,7 +367,7 @@ class DeviceTypeFilter(CustomFieldFilterSet):
|
||||
)
|
||||
|
||||
|
||||
class DeviceTypeComponentFilterSet(django_filters.FilterSet):
|
||||
class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet):
|
||||
devicetype_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=DeviceType.objects.all(),
|
||||
field_name='device_type_id',
|
||||
@@ -447,14 +431,14 @@ class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
|
||||
fields = ['name']
|
||||
|
||||
|
||||
class DeviceRoleFilter(django_filters.FilterSet):
|
||||
class DeviceRoleFilter(NameSlugSearchFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = DeviceRole
|
||||
fields = ['name', 'slug', 'color', 'vm_role']
|
||||
|
||||
|
||||
class PlatformFilter(django_filters.FilterSet):
|
||||
class PlatformFilter(NameSlugSearchFilterSet):
|
||||
manufacturer_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='manufacturer',
|
||||
queryset=Manufacturer.objects.all(),
|
||||
@@ -686,6 +670,10 @@ class DeviceFilter(CustomFieldFilterSet):
|
||||
|
||||
|
||||
class DeviceComponentFilterSet(django_filters.FilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
device_id = django_filters.ModelChoiceFilter(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device (ID)',
|
||||
@@ -697,6 +685,13 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
|
||||
)
|
||||
tag = TagFilter()
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value)
|
||||
)
|
||||
|
||||
|
||||
class ConsolePortFilter(DeviceComponentFilterSet):
|
||||
cabled = django_filters.BooleanFilter(
|
||||
@@ -750,6 +745,10 @@ class InterfaceFilter(django_filters.FilterSet):
|
||||
"""
|
||||
Not using DeviceComponentFilterSet for Interfaces because we need to check for VirtualChassis membership.
|
||||
"""
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
device = django_filters.CharFilter(
|
||||
method='filter_device',
|
||||
field_name='name',
|
||||
@@ -796,6 +795,13 @@ class InterfaceFilter(django_filters.FilterSet):
|
||||
model = Interface
|
||||
fields = ['name', 'connection_status', 'form_factor', 'enabled', 'mtu', 'mgmt_only']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value)
|
||||
).distinct()
|
||||
|
||||
def filter_device(self, queryset, name, value):
|
||||
try:
|
||||
device = Device.objects.get(**{name: value})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,11 @@ class ComponentModel(models.Model):
|
||||
"""
|
||||
Log an ObjectChange including the parent Device/VM.
|
||||
"""
|
||||
parent = self.device if self.device is not None else getattr(self, 'virtual_machine', None)
|
||||
try:
|
||||
parent = getattr(self, 'device', None) or getattr(self, 'virtual_machine', None)
|
||||
except ObjectDoesNotExist:
|
||||
# The parent device/VM has already been deleted
|
||||
parent = None
|
||||
ObjectChange(
|
||||
user=user,
|
||||
request_id=request_id,
|
||||
@@ -64,6 +68,10 @@ class ComponentModel(models.Model):
|
||||
object_data=serialize_object(self)
|
||||
).save()
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return getattr(self, 'device', None)
|
||||
|
||||
|
||||
class CableTermination(models.Model):
|
||||
cable = models.ForeignKey(
|
||||
@@ -158,6 +166,14 @@ class CableTermination(models.Model):
|
||||
|
||||
return path + next_segment
|
||||
|
||||
def get_cable_peer(self):
|
||||
if self.cable is None:
|
||||
return None
|
||||
if self._cabled_as_a:
|
||||
return self.cable.termination_b
|
||||
if self._cabled_as_b:
|
||||
return self.cable.termination_a
|
||||
|
||||
|
||||
#
|
||||
# Regions
|
||||
@@ -201,6 +217,13 @@ class Region(MPTTModel, ChangeLoggedModel):
|
||||
self.parent.name if self.parent else None,
|
||||
)
|
||||
|
||||
@property
|
||||
def site_count(self):
|
||||
return Site.objects.filter(
|
||||
Q(region=self) |
|
||||
Q(region__in=self.get_descendants())
|
||||
).count()
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
@@ -2551,9 +2574,12 @@ class Cable(ChangeLoggedModel):
|
||||
|
||||
def clean(self):
|
||||
|
||||
# Check that termination types are compatible
|
||||
if self.termination_a and self.termination_b:
|
||||
|
||||
type_a = self.termination_a_type.model
|
||||
type_b = self.termination_b_type.model
|
||||
|
||||
# Check that termination types are compatible
|
||||
if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a):
|
||||
raise ValidationError("Incompatible termination types: {} and {}".format(
|
||||
self.termination_a_type, self.termination_b_type
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import re
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||
@@ -50,7 +52,16 @@ class BulkRenameView(GetReturnURLMixin, View):
|
||||
|
||||
if form.is_valid():
|
||||
for obj in selected_objects:
|
||||
obj.new_name = obj.name.replace(form.cleaned_data['find'], form.cleaned_data['replace'])
|
||||
find = form.cleaned_data['find']
|
||||
replace = form.cleaned_data['replace']
|
||||
if form.cleaned_data['use_regex']:
|
||||
try:
|
||||
obj.new_name = re.sub(find, replace, obj.name)
|
||||
# Catch regex group reference errors
|
||||
except re.error:
|
||||
obj.new_name = obj.name
|
||||
else:
|
||||
obj.new_name = obj.name.replace(find, replace)
|
||||
|
||||
if '_apply' in request.POST:
|
||||
for obj in selected_objects:
|
||||
@@ -124,7 +135,7 @@ class BulkDisconnectView(GetReturnURLMixin, View):
|
||||
#
|
||||
|
||||
class RegionListView(ObjectListView):
|
||||
queryset = Region.objects.annotate(site_count=Count('sites'))
|
||||
queryset = Region.objects.all()
|
||||
filter = filters.RegionFilter
|
||||
filter_form = forms.RegionFilterForm
|
||||
table = tables.RegionTable
|
||||
@@ -151,7 +162,7 @@ class RegionBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
|
||||
class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dcim.delete_region'
|
||||
queryset = Region.objects.annotate(site_count=Count('sites'))
|
||||
queryset = Region.objects.all()
|
||||
filter = filters.RegionFilter
|
||||
table = tables.RegionTable
|
||||
default_return_url = 'dcim:region_list'
|
||||
@@ -1771,14 +1782,20 @@ class InterfaceConnectionsListView(ObjectListView):
|
||||
def queryset_to_csv(self):
|
||||
csv_data = [
|
||||
# Headers
|
||||
','.join(['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status'])
|
||||
','.join([
|
||||
'device_a', 'interface_a', 'interface_a_description',
|
||||
'device_b', 'interface_b', 'interface_b_description',
|
||||
'connection_status'
|
||||
])
|
||||
]
|
||||
for obj in self.queryset:
|
||||
csv = csv_format([
|
||||
obj.connected_endpoint.device.identifier if obj.connected_endpoint else None,
|
||||
obj.connected_endpoint.name if obj.connected_endpoint else None,
|
||||
obj.connected_endpoint.description if obj.connected_endpoint else None,
|
||||
obj.device.identifier,
|
||||
obj.name,
|
||||
obj.description,
|
||||
obj.get_connection_status_display(),
|
||||
])
|
||||
csv_data.append(csv)
|
||||
|
||||
@@ -99,10 +99,9 @@ class TopologyMapViewSet(ModelViewSet):
|
||||
|
||||
try:
|
||||
data = tmap.render(img_format=img_format)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
return HttpResponse(
|
||||
"There was an error generating the requested graph. Ensure that the GraphViz executables have been "
|
||||
"installed correctly."
|
||||
"There was an error generating the requested graph: %s" % e
|
||||
)
|
||||
|
||||
response = HttpResponse(data, content_type='image/{}'.format(img_format))
|
||||
|
||||
@@ -7,7 +7,7 @@ from netaddr.core import AddrFormatError
|
||||
from dcim.models import Site, Device, Interface
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NumericInFilter, TagFilter
|
||||
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
||||
from virtualization.models import VirtualMachine
|
||||
from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES
|
||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||
@@ -48,7 +48,7 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
fields = ['name', 'rd', 'enforce_unique']
|
||||
|
||||
|
||||
class RIRFilter(django_filters.FilterSet):
|
||||
class RIRFilter(NameSlugSearchFilterSet):
|
||||
id__in = NumericInFilter(
|
||||
field_name='id',
|
||||
lookup_expr='in'
|
||||
@@ -96,7 +96,11 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class RoleFilter(django_filters.FilterSet):
|
||||
class RoleFilter(NameSlugSearchFilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
@@ -373,7 +377,7 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
return queryset.none()
|
||||
|
||||
|
||||
class VLANGroupFilter(django_filters.FilterSet):
|
||||
class VLANGroupFilter(NameSlugSearchFilterSet):
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from django import forms
|
||||
from django.core.exceptions import MultipleObjectsReturned
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site, Rack, Device, Interface
|
||||
@@ -9,9 +8,9 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
||||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
AnnotatedMultipleChoiceField, APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
||||
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, ReturnURLForm,
|
||||
SlugField, add_blank_choice,
|
||||
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
||||
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, SlugField,
|
||||
StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
from virtualization.models import VirtualMachine
|
||||
from .constants import (
|
||||
@@ -77,7 +76,10 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
enforce_unique = forms.NullBooleanField(
|
||||
required=False,
|
||||
@@ -102,11 +104,14 @@ class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
label='Search'
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('vrfs')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -139,12 +144,8 @@ class RIRFilterForm(BootstrapMixin, forms.Form):
|
||||
is_private = forms.NullBooleanField(
|
||||
required=False,
|
||||
label='Private',
|
||||
widget=forms.Select(
|
||||
choices=[
|
||||
('', '---------'),
|
||||
('True', 'Yes'),
|
||||
('False', 'No'),
|
||||
]
|
||||
widget=StaticSelect2(
|
||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
)
|
||||
|
||||
@@ -168,6 +169,11 @@ class AggregateForm(BootstrapMixin, CustomFieldForm):
|
||||
'rir': "Regional Internet Registry responsible for this prefix",
|
||||
'date_added': "Format: YYYY-MM-DD",
|
||||
}
|
||||
widgets = {
|
||||
'rir': APISelect(
|
||||
api_url="/api/ipam/rirs/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class AggregateCSVForm(forms.ModelForm):
|
||||
@@ -193,7 +199,10 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
||||
rir = forms.ModelChoiceField(
|
||||
queryset=RIR.objects.all(),
|
||||
required=False,
|
||||
label='RIR'
|
||||
label='RIR',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/rirs/"
|
||||
)
|
||||
)
|
||||
date_added = forms.DateField(
|
||||
required=False
|
||||
@@ -218,12 +227,17 @@ class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
rir = FilterChoiceField(
|
||||
queryset=RIR.objects.annotate(filter_count=Count('aggregates')),
|
||||
queryset=RIR.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='RIR'
|
||||
label='RIR',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/rirs/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -261,9 +275,13 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label='Site',
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'vlan_group': 'site_id',
|
||||
'vlan': 'site_id',
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'vlan_group',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
@@ -276,9 +294,11 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
required=False,
|
||||
label='VLAN group',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
||||
api_url='/api/ipam/vlan-groups/',
|
||||
filter_for={
|
||||
'vlan': 'group_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'vlan',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
@@ -292,7 +312,7 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
required=False,
|
||||
label='VLAN',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}',
|
||||
api_url='/api/ipam/vlans/',
|
||||
display_field='display_name'
|
||||
)
|
||||
)
|
||||
@@ -304,6 +324,15 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant',
|
||||
'tags',
|
||||
]
|
||||
widgets = {
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
),
|
||||
'status': StaticSelect2(),
|
||||
'role': APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@@ -415,24 +444,42 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
||||
)
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
)
|
||||
vrf = forms.ModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF'
|
||||
label='VRF',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
prefix_length = forms.IntegerField(
|
||||
min_value=1,
|
||||
max_value=127,
|
||||
required=False
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(PREFIX_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=Role.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
)
|
||||
is_pool = forms.NullBooleanField(
|
||||
required=False,
|
||||
@@ -468,47 +515,67 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
mask_length = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=PREFIX_MASK_LENGTH_CHOICES,
|
||||
label='Mask length'
|
||||
label='Mask length',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
vrf = FilterChoiceField(
|
||||
queryset=VRF.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vrfs/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=PREFIX_STATUS_CHOICES,
|
||||
annotate=Prefix.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/roles/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
is_pool = forms.NullBooleanField(
|
||||
required=False,
|
||||
label='Is a pool',
|
||||
widget=StaticSelect2(
|
||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
)
|
||||
expand = forms.BooleanField(
|
||||
required=False,
|
||||
@@ -529,9 +596,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label='Site',
|
||||
widget=forms.Select(
|
||||
attrs={
|
||||
'filter-for': 'nat_rack'
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'nat_rack': 'site_id',
|
||||
'nat_device': 'site_id'
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -543,10 +612,12 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
required=False,
|
||||
label='Rack',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{nat_site}}',
|
||||
api_url='/api/dcim/racks/',
|
||||
display_field='display_name',
|
||||
filter_for={
|
||||
'nat_device': 'rack_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'nat_device',
|
||||
'nullable': 'true'
|
||||
}
|
||||
)
|
||||
@@ -560,9 +631,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
required=False,
|
||||
label='Device',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{nat_site}}&rack_id={{nat_rack}}',
|
||||
api_url='/api/dcim/devices/',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'nat_inside'}
|
||||
filter_for={
|
||||
'nat_inside': 'device_id'
|
||||
}
|
||||
)
|
||||
)
|
||||
nat_inside = ChainedModelChoiceField(
|
||||
@@ -573,20 +646,10 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
required=False,
|
||||
label='IP Address',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}',
|
||||
api_url='/api/ipam/ip-addresses/',
|
||||
display_field='address'
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='Search',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='ipam-api:ipaddress-list',
|
||||
field_to_update='nat_inside',
|
||||
obj_label='address'
|
||||
)
|
||||
)
|
||||
primary_for_parent = forms.BooleanField(
|
||||
required=False,
|
||||
label='Make this the primary IP for the device/VM'
|
||||
@@ -601,6 +664,13 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
'address', 'vrf', 'status', 'role', 'description', 'interface', 'primary_for_parent', 'nat_site',
|
||||
'nat_rack', 'nat_inside', 'tenant_group', 'tenant', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': StaticSelect2(),
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@@ -680,6 +750,13 @@ class IPAddressBulkAddForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
fields = [
|
||||
'address', 'vrf', 'status', 'role', 'description', 'tenant_group', 'tenant',
|
||||
]
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': StaticSelect2(),
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -817,19 +894,32 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
||||
vrf = forms.ModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF'
|
||||
label='VRF',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
mask_length = forms.IntegerField(
|
||||
min_value=1,
|
||||
max_value=128,
|
||||
required=False
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(IPADDRESS_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ChoiceField(
|
||||
choices=add_blank_choice(IPADDRESS_ROLE_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
description = forms.CharField(
|
||||
max_length=100, required=False
|
||||
@@ -846,7 +936,10 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF',
|
||||
empty_label='Global'
|
||||
empty_label='Global',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
address = forms.CharField(
|
||||
label='IP Address'
|
||||
@@ -871,39 +964,45 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
mask_length = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IPADDRESS_MASK_LENGTH_CHOICES,
|
||||
label='Mask length'
|
||||
label='Mask length',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
vrf = FilterChoiceField(
|
||||
queryset=VRF.objects.annotate(
|
||||
filter_count=Count('ip_addresses')
|
||||
),
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vrfs/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('ip_addresses')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=IPADDRESS_STATUS_CHOICES,
|
||||
annotate=IPAddress.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
role = AnnotatedMultipleChoiceField(
|
||||
role = forms.MultipleChoiceField(
|
||||
choices=IPADDRESS_ROLE_CHOICES,
|
||||
annotate=IPAddress.objects.all(),
|
||||
annotate_field='role',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
|
||||
|
||||
@@ -919,6 +1018,11 @@ class VLANGroupForm(BootstrapMixin, forms.ModelForm):
|
||||
fields = [
|
||||
'site', 'name', 'slug',
|
||||
]
|
||||
widgets = {
|
||||
'site': APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class VLANGroupCSVForm(forms.ModelForm):
|
||||
@@ -943,11 +1047,14 @@ class VLANGroupCSVForm(forms.ModelForm):
|
||||
|
||||
class VLANGroupFilterForm(BootstrapMixin, forms.Form):
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('vlan_groups')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -959,9 +1066,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'group': 'site_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'group',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
@@ -974,7 +1084,7 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
required=False,
|
||||
label='Group',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
||||
api_url='/api/ipam/vlan-groups/',
|
||||
)
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
@@ -992,6 +1102,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
'status': "Operational status of this VLAN",
|
||||
'role': "The primary function of this VLAN",
|
||||
}
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class VLANCSVForm(forms.ModelForm):
|
||||
@@ -1067,23 +1183,36 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
||||
)
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
)
|
||||
group = forms.ModelChoiceField(
|
||||
queryset=VLANGroup.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vlan-groups/"
|
||||
)
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(VLAN_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=Role.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
)
|
||||
description = forms.CharField(
|
||||
max_length=100,
|
||||
@@ -1103,38 +1232,48 @@ class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
label='Search'
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
group_id = FilterChoiceField(
|
||||
queryset=VLANGroup.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=VLANGroup.objects.all(),
|
||||
label='VLAN group',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vlan-groups/",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=VLAN_STATUS_CHOICES,
|
||||
annotate=VLAN.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/roles/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1156,6 +1295,10 @@ class ServiceForm(BootstrapMixin, CustomFieldForm):
|
||||
'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be "
|
||||
"reachable via all IPs assigned to the device.",
|
||||
}
|
||||
widgets = {
|
||||
'protocol': StaticSelect2(),
|
||||
'ipaddresses': StaticSelect2Multiple(),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -1182,10 +1325,11 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
protocol = forms.ChoiceField(
|
||||
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
port = forms.IntegerField(
|
||||
required=False
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -1196,7 +1340,8 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
)
|
||||
protocol = forms.ChoiceField(
|
||||
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
port = forms.IntegerField(
|
||||
validators=[
|
||||
@@ -1212,5 +1357,5 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
|
||||
class Meta:
|
||||
nullable_fields = [
|
||||
'site', 'group', 'tenant', 'role', 'description',
|
||||
'site', 'tenant', 'role', 'description',
|
||||
]
|
||||
|
||||
18
netbox/ipam/migrations/0024_vrf_allow_null_rd.py
Normal file
18
netbox/ipam/migrations/0024_vrf_allow_null_rd.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2019-01-31 18:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0023_change_logging'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='vrf',
|
||||
name='rd',
|
||||
field=models.CharField(blank=True, max_length=21, null=True, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -29,6 +29,8 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
|
||||
rd = models.CharField(
|
||||
max_length=21,
|
||||
unique=True,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Route distinguisher'
|
||||
)
|
||||
tenant = models.ForeignKey(
|
||||
@@ -385,6 +387,15 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
||||
self.description,
|
||||
)
|
||||
|
||||
def _set_prefix_length(self, value):
|
||||
"""
|
||||
Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
|
||||
e.g. for bulk editing.
|
||||
"""
|
||||
if self.prefix is not None:
|
||||
self.prefix.prefixlen = value
|
||||
prefix_length = property(fset=_set_prefix_length)
|
||||
|
||||
def get_status_class(self):
|
||||
return STATUS_CHOICE_CLASSES[self.status]
|
||||
|
||||
@@ -429,8 +440,19 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
|
||||
child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()])
|
||||
available_ips = prefix - child_ips
|
||||
|
||||
# Remove unusable IPs from non-pool prefixes
|
||||
if not self.is_pool:
|
||||
# All IP addresses within a pool are considered usable
|
||||
if self.is_pool:
|
||||
return available_ips
|
||||
|
||||
# All IP addresses within a point-to-point prefix (IPv4 /31 or IPv6 /127) are considered usable
|
||||
if (
|
||||
self.family == 4 and self.prefix.prefixlen == 31 # RFC 3021
|
||||
) or (
|
||||
self.family == 6 and self.prefix.prefixlen == 127 # RFC 6164
|
||||
):
|
||||
return available_ips
|
||||
|
||||
# Omit first and last IP address from the available set
|
||||
available_ips -= netaddr.IPSet([
|
||||
netaddr.IPAddress(self.prefix.first),
|
||||
netaddr.IPAddress(self.prefix.last),
|
||||
@@ -630,6 +652,15 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
|
||||
self.description,
|
||||
)
|
||||
|
||||
def _set_mask_length(self, value):
|
||||
"""
|
||||
Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
|
||||
e.g. for bulk editing.
|
||||
"""
|
||||
if self.address is not None:
|
||||
self.address.prefixlen = value
|
||||
mask_length = property(fset=_set_mask_length)
|
||||
|
||||
@property
|
||||
def device(self):
|
||||
if self.interface:
|
||||
|
||||
@@ -16,7 +16,7 @@ class VRFTest(APITestCase):
|
||||
|
||||
self.vrf1 = VRF.objects.create(name='Test VRF 1', rd='65000:1')
|
||||
self.vrf2 = VRF.objects.create(name='Test VRF 2', rd='65000:2')
|
||||
self.vrf3 = VRF.objects.create(name='Test VRF 3', rd='65000:3')
|
||||
self.vrf3 = VRF.objects.create(name='Test VRF 3') # No RD
|
||||
|
||||
def test_get_vrf(self):
|
||||
|
||||
@@ -44,19 +44,26 @@ class VRFTest(APITestCase):
|
||||
|
||||
def test_create_vrf(self):
|
||||
|
||||
data = {
|
||||
data_list = [
|
||||
# VRF with RD
|
||||
{
|
||||
'name': 'Test VRF 4',
|
||||
'rd': '65000:4',
|
||||
},
|
||||
# VRF without RD
|
||||
{
|
||||
'name': 'Test VRF 5',
|
||||
}
|
||||
]
|
||||
|
||||
url = reverse('ipam-api:vrf-list')
|
||||
response = self.client.post(url, data, format='json', **self.header)
|
||||
|
||||
for data in data_list:
|
||||
response = self.client.post(url, data, format='json', **self.header)
|
||||
self.assertHttpStatus(response, status.HTTP_201_CREATED)
|
||||
self.assertEqual(VRF.objects.count(), 4)
|
||||
vrf4 = VRF.objects.get(pk=response.data['id'])
|
||||
self.assertEqual(vrf4.name, data['name'])
|
||||
self.assertEqual(vrf4.rd, data['rd'])
|
||||
vrf = VRF.objects.get(pk=response.data['id'])
|
||||
self.assertEqual(vrf.name, data['name'])
|
||||
self.assertEqual(vrf.rd, data['rd'] if 'rd' in data else None)
|
||||
|
||||
def test_create_vrf_bulk(self):
|
||||
|
||||
|
||||
@@ -126,14 +126,11 @@ class VRFView(View):
|
||||
def get(self, request, pk):
|
||||
|
||||
vrf = get_object_or_404(VRF.objects.all(), pk=pk)
|
||||
prefix_table = tables.PrefixTable(
|
||||
list(Prefix.objects.filter(vrf=vrf).select_related('site', 'role')), orderable=False
|
||||
)
|
||||
prefix_table.exclude = ('vrf',)
|
||||
prefix_count = Prefix.objects.filter(vrf=vrf).count()
|
||||
|
||||
return render(request, 'ipam/vrf.html', {
|
||||
'vrf': vrf,
|
||||
'prefix_table': prefix_table,
|
||||
'prefix_count': prefix_count,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ OBJ_TYPE_CHOICES = (
|
||||
('devicetype', 'Device types'),
|
||||
('device', 'Devices'),
|
||||
('virtualchassis', 'Virtual Chassis'),
|
||||
('cable', 'Cables'),
|
||||
)),
|
||||
('IPAM', (
|
||||
('vrf', 'VRFs'),
|
||||
|
||||
@@ -22,7 +22,7 @@ except ImportError:
|
||||
)
|
||||
|
||||
|
||||
VERSION = '2.5.2'
|
||||
VERSION = '2.5.5'
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
@@ -246,6 +246,14 @@ LOGIN_URL = '/{}login/'.format(BASE_PATH)
|
||||
# Secrets
|
||||
SECRETS_MIN_PUBKEY_SIZE = 2048
|
||||
|
||||
# Pagination
|
||||
PER_PAGE_DEFAULTS = [
|
||||
25, 50, 100, 250, 500, 1000
|
||||
]
|
||||
if PAGINATE_COUNT not in PER_PAGE_DEFAULTS:
|
||||
PER_PAGE_DEFAULTS.append(PAGINATE_COUNT)
|
||||
PER_PAGE_DEFAULTS = sorted(PER_PAGE_DEFAULTS)
|
||||
|
||||
# Django filters
|
||||
FILTERS_NULL_CHOICE_LABEL = 'None'
|
||||
FILTERS_NULL_CHOICE_VALUE = 'null'
|
||||
|
||||
@@ -11,13 +11,13 @@ from circuits.filters import CircuitFilter, ProviderFilter
|
||||
from circuits.models import Circuit, Provider
|
||||
from circuits.tables import CircuitTable, ProviderTable
|
||||
from dcim.filters import (
|
||||
DeviceFilter, DeviceTypeFilter, RackFilter, RackGroupFilter, SiteFilter, VirtualChassisFilter
|
||||
CableFilter, DeviceFilter, DeviceTypeFilter, RackFilter, RackGroupFilter, SiteFilter, VirtualChassisFilter
|
||||
)
|
||||
from dcim.models import (
|
||||
Cable, ConsolePort, Device, DeviceType, Interface, PowerPort, Rack, RackGroup, Site, VirtualChassis
|
||||
)
|
||||
from dcim.tables import (
|
||||
DeviceDetailTable, DeviceTypeTable, RackTable, RackGroupTable, SiteTable, VirtualChassisTable
|
||||
CableTable, DeviceDetailTable, DeviceTypeTable, RackTable, RackGroupTable, SiteTable, VirtualChassisTable
|
||||
)
|
||||
from extras.models import ObjectChange, ReportResult, TopologyMap
|
||||
from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter
|
||||
@@ -88,6 +88,12 @@ SEARCH_TYPES = OrderedDict((
|
||||
'table': VirtualChassisTable,
|
||||
'url': 'dcim:virtualchassis_list',
|
||||
}),
|
||||
('cable', {
|
||||
'queryset': Cable.objects.all(),
|
||||
'filter': CableFilter,
|
||||
'table': CableTable,
|
||||
'url': 'dcim:cable_list',
|
||||
}),
|
||||
# IPAM
|
||||
('vrf', {
|
||||
'queryset': VRF.objects.select_related('tenant'),
|
||||
|
||||
@@ -120,6 +120,117 @@ input[name="pk"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Color Selections */
|
||||
.color-selection-aa1409 {
|
||||
background-color: #aa1409;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-f44336 {
|
||||
background-color: #f44336;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-e91e63 {
|
||||
background-color: #e91e63;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ffe4e1 {
|
||||
background-color: #ffe4e1;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ff66ff {
|
||||
background-color: #ff66ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-9c27b0 {
|
||||
background-color: #9c27b0;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-673ab7 {
|
||||
background-color: #673ab7;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-3f51b5 {
|
||||
background-color: #3f51b5;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-2196f3 {
|
||||
background-color: #2196f3;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-03a9f4 {
|
||||
background-color: #03a9f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-00bcd4 {
|
||||
background-color: #00bcd4;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-009688 {
|
||||
background-color: #009688;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-00ffff {
|
||||
background-color: #00ffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-2f6a31 {
|
||||
background-color: #2f6a31;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-4caf50 {
|
||||
background-color: #4caf50;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-8bc34a {
|
||||
background-color: #8bc34a;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-cddc39 {
|
||||
background-color: #cddc39;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ffeb3b {
|
||||
background-color: #ffeb3b;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ffc107 {
|
||||
background-color: #ffc107;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ff9800 {
|
||||
background-color: #ff9800;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ff5722 {
|
||||
background-color: #ff5722;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-795548 {
|
||||
background-color: #795548;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-c0c0c0 {
|
||||
background-color: #c0c0c0;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-9e9e9e {
|
||||
background-color: #9e9e9e;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-607d8b {
|
||||
background-color: #607d8b;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-111111 {
|
||||
background-color: #111111;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ffffff {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
/* Tables */
|
||||
th.pk, td.pk {
|
||||
padding-bottom: 6px;
|
||||
@@ -140,6 +251,9 @@ table.attr-table td:nth-child(1) {
|
||||
div.paginator {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
div.paginator form {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
nav ul.pagination {
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px !important;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// Pagination
|
||||
$('select#per_page').change(function() {
|
||||
this.form.submit();
|
||||
});
|
||||
|
||||
// "Toggle" checkbox for object lists (PK column)
|
||||
$('input:checkbox.toggle').click(function() {
|
||||
$(this).closest('table').find('input:checkbox[name=pk]').prop('checked', $(this).prop('checked'));
|
||||
@@ -62,37 +67,13 @@ $(document).ready(function() {
|
||||
form.submit();
|
||||
});
|
||||
|
||||
// API select widget
|
||||
$('select[filter-for]').change(function() {
|
||||
|
||||
// Resolve child field by ID specified in parent
|
||||
var child_names = $(this).attr('filter-for');
|
||||
var parent = this;
|
||||
|
||||
// allow more than one child
|
||||
$.each(child_names.split(" "), function(_, child_name){
|
||||
|
||||
var child_field = $('#id_' + child_name);
|
||||
var child_selected = child_field.val();
|
||||
|
||||
// Wipe out any existing options within the child field and create a default option
|
||||
child_field.empty();
|
||||
if (!child_field.attr('multiple')) {
|
||||
child_field.append($("<option></option>").attr("value", "").text("---------"));
|
||||
}
|
||||
|
||||
if ($(parent).val() || $(parent).attr('nullable') == 'true') {
|
||||
var api_url = child_field.attr('api-url') + '&limit=0&brief=1';
|
||||
var disabled_indicator = child_field.attr('disabled-indicator');
|
||||
var initial_value = child_field.attr('initial');
|
||||
var display_field = child_field.attr('display-field') || 'name';
|
||||
|
||||
// Determine the filter fields needed to make an API call
|
||||
// Parse URLs which may contain variable refrences to other field values
|
||||
function parseURL(url) {
|
||||
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
||||
var match;
|
||||
var rendered_url = api_url;
|
||||
var rendered_url = url;
|
||||
var filter_field;
|
||||
while (match = filter_regex.exec(api_url)) {
|
||||
while (match = filter_regex.exec(url)) {
|
||||
filter_field = $('#id_' + match[1]);
|
||||
var custom_attr = $('option:selected', filter_field).attr('api-value');
|
||||
if (custom_attr) {
|
||||
@@ -103,94 +84,206 @@ $(document).ready(function() {
|
||||
rendered_url = rendered_url.replace(match[0], 'null');
|
||||
}
|
||||
}
|
||||
return rendered_url
|
||||
}
|
||||
|
||||
// Account for any conditional URL append strings
|
||||
$.each(child_field[0].attributes, function(index, attr){
|
||||
if (attr.name.includes("data-url-conditional-append-")){
|
||||
var conditional = attr.name.split("data-url-conditional-append-")[1].split("__");
|
||||
// Assign color picker selection classes
|
||||
function colorPickerClassCopy(data, container) {
|
||||
if (data.element) {
|
||||
$(container).addClass($(data.element).attr("class"));
|
||||
}
|
||||
return data.text;
|
||||
}
|
||||
|
||||
// Color Picker
|
||||
$('.netbox-select2-color-picker').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
theme: "bootstrap",
|
||||
templateResult: colorPickerClassCopy,
|
||||
templateSelection: colorPickerClassCopy
|
||||
});
|
||||
|
||||
// Static choice selection
|
||||
$('.netbox-select2-static').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
theme: "bootstrap"
|
||||
});
|
||||
|
||||
// API backed selection
|
||||
// Includes live search and chained fields
|
||||
// The `multiple` setting may be controled via a data-* attribute
|
||||
$('.netbox-select2-api').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
theme: "bootstrap",
|
||||
ajax: {
|
||||
delay: 500,
|
||||
|
||||
url: function(params) {
|
||||
var element = this[0];
|
||||
var url = parseURL(element.getAttribute("data-url"));
|
||||
|
||||
if (url.includes("{{")) {
|
||||
// URL is not fully rendered yet, abort the request
|
||||
return false;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
data: function(params) {
|
||||
var element = this[0];
|
||||
// Paging. Note that `params.page` indexes at 1
|
||||
var offset = (params.page - 1) * 50 || 0;
|
||||
// Base query params
|
||||
var parameters = {
|
||||
q: params.term,
|
||||
brief: 1,
|
||||
limit: 50,
|
||||
offset: offset,
|
||||
};
|
||||
|
||||
// filter-for fields from a chain
|
||||
var attr_name = "data-filter-for-" + $(element).attr("name");
|
||||
var form = $(element).closest('form');
|
||||
var filter_for_elements = form.find("select[" + attr_name + "]");
|
||||
|
||||
filter_for_elements.each(function(index, filter_for_element) {
|
||||
var param_name = $(filter_for_element).attr(attr_name);
|
||||
var value = $(filter_for_element).val();
|
||||
|
||||
if (param_name && value) {
|
||||
parameters[param_name] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Conditional query params
|
||||
$.each(element.attributes, function(index, attr){
|
||||
if (attr.name.includes("data-conditional-query-param-")){
|
||||
var conditional = attr.name.split("data-conditional-query-param-")[1].split("__");
|
||||
var field = $("#id_" + conditional[0]);
|
||||
var field_value = conditional[1];
|
||||
|
||||
if ($('option:selected', field).attr('api-value') === field_value){
|
||||
rendered_url = rendered_url + attr.value;
|
||||
var _val = attr.value.split("=");
|
||||
parameters[_val[0]] = _val[1];
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// If all URL variables have been replaced, make the API call
|
||||
if (rendered_url.search('{{') < 0) {
|
||||
console.log(child_name + ": Fetching " + rendered_url);
|
||||
$.ajax({
|
||||
url: rendered_url,
|
||||
dataType: 'json',
|
||||
success: function(response, status) {
|
||||
$.each(response.results, function(index, choice) {
|
||||
var option = $("<option></option>").attr("value", choice.id).text(choice[display_field]);
|
||||
if (disabled_indicator && choice[disabled_indicator] && choice.id != initial_value) {
|
||||
option.attr("disabled", "disabled");
|
||||
} else if (choice.id == child_selected) {
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
child_field.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Trigger change event in case the child field is the parent of another field
|
||||
child_field.change();
|
||||
});
|
||||
|
||||
// Additional query params
|
||||
$.each(element.attributes, function(index, attr){
|
||||
if (attr.name.includes("data-additional-query-param-")){
|
||||
var param_name = attr.name.split("data-additional-query-param-")[1]
|
||||
parameters[param_name] = attr.value;
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-complete tags
|
||||
function split_tags(val) {
|
||||
return val.split(/,\s*/);
|
||||
}
|
||||
$("#id_tags")
|
||||
.on("keydown", function(event) {
|
||||
if (event.keyCode === $.ui.keyCode.TAB &&
|
||||
$(this).autocomplete("instance").menu.active) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
.autocomplete({
|
||||
source: function(request, response) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: netbox_api_path + 'extras/tags/',
|
||||
data: 'q=' + split_tags(request.term).pop(),
|
||||
success: function(data) {
|
||||
var choices = [];
|
||||
$.each(data.results, function (index, choice) {
|
||||
choices.push(choice.name);
|
||||
});
|
||||
response(choices);
|
||||
}
|
||||
});
|
||||
// This will handle params with multiple values (i.e. for list filter forms)
|
||||
return $.param(parameters, true);
|
||||
},
|
||||
search: function() {
|
||||
// Need 3 or more characters to begin searching
|
||||
var term = split_tags(this.value).pop();
|
||||
if (term.length < 3) {
|
||||
return false;
|
||||
|
||||
processResults: function (data) {
|
||||
var element = this.$element[0];
|
||||
var results = $.map(data.results, function (obj) {
|
||||
obj.text = obj[element.getAttribute('display-field')] || obj.name;
|
||||
obj.id = obj[element.getAttribute('value-field')] || obj.id;
|
||||
|
||||
if(element.getAttribute('disabled-indicator') && obj[element.getAttribute('disabled-indicator')]) {
|
||||
// The disabled-indicator equated to true, so we disable this option
|
||||
obj.disabled = true;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
// Handle the null option, but only add it once
|
||||
if (element.getAttribute('data-null-option') && data.previous === null) {
|
||||
var null_option = $(element).children()[0]
|
||||
results.unshift({
|
||||
id: null_option.value,
|
||||
text: null_option.text
|
||||
});
|
||||
}
|
||||
|
||||
// Check if there are more results to page
|
||||
var page = data.next !== null;
|
||||
return {
|
||||
results: results,
|
||||
pagination: {
|
||||
more: page
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// API backed tags
|
||||
var tags = $('#id_tags');
|
||||
if (tags.length > 0 && tags.val().length > 0){
|
||||
tags = $('#id_tags').val().split(/,\s*/);
|
||||
} else {
|
||||
tags = [];
|
||||
}
|
||||
tag_objs = $.map(tags, function (tag) {
|
||||
return {
|
||||
id: tag,
|
||||
text: tag,
|
||||
selected: true
|
||||
}
|
||||
});
|
||||
// Replace the django issued text input with a select element
|
||||
$('#id_tags').replaceWith('<select name="tags" id="id_tags" class="form-control"></select>');
|
||||
$('#id_tags').select2({
|
||||
tags: true,
|
||||
data: tag_objs,
|
||||
multiple: true,
|
||||
allowClear: true,
|
||||
placeholder: "Tags",
|
||||
|
||||
ajax: {
|
||||
delay: 250,
|
||||
url: "/api/extras/tags/",
|
||||
|
||||
data: function(params) {
|
||||
// Paging. Note that `params.page` indexes at 1
|
||||
var offset = (params.page - 1) * 50 || 0;
|
||||
var parameters = {
|
||||
q: params.term,
|
||||
brief: 1,
|
||||
limit: 50,
|
||||
offset: offset,
|
||||
};
|
||||
return parameters;
|
||||
},
|
||||
focus: function() {
|
||||
// prevent value inserted on focus
|
||||
return false;
|
||||
},
|
||||
select: function(event, ui) {
|
||||
var terms = split_tags(this.value);
|
||||
// remove the current input
|
||||
terms.pop();
|
||||
// add the selected item
|
||||
terms.push(ui.item.value);
|
||||
// add placeholder to get the comma-and-space at the end
|
||||
terms.push("");
|
||||
this.value = terms.join(", ");
|
||||
return false;
|
||||
|
||||
processResults: function (data) {
|
||||
var results = $.map(data.results, function (obj) {
|
||||
return {
|
||||
id: obj.name,
|
||||
text: obj.name
|
||||
}
|
||||
});
|
||||
|
||||
// Check if there are more results to page
|
||||
var page = data.next !== null;
|
||||
return {
|
||||
results: results,
|
||||
pagination: {
|
||||
more: page
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#id_tags').closest('form').submit(function(event){
|
||||
// django-taggit can only accept a single comma seperated string value
|
||||
var value = $('#id_tags').val();
|
||||
if (value.length > 0){
|
||||
var final_tags = value.join(', ');
|
||||
$('#id_tags').val(null).trigger('change');
|
||||
var option = new Option(final_tags, final_tags, true, true);
|
||||
$('#id_tags').append(option).trigger('change');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
21
netbox/project-static/select2-4.0.5/LICENSE.md
Executable file
21
netbox/project-static/select2-4.0.5/LICENSE.md
Executable file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
123
netbox/project-static/select2-4.0.5/README.md
Executable file
123
netbox/project-static/select2-4.0.5/README.md
Executable file
@@ -0,0 +1,123 @@
|
||||
Select2
|
||||
=======
|
||||
[![Build Status][travis-ci-image]][travis-ci-status]
|
||||
|
||||
Select2 is a jQuery-based replacement for select boxes. It supports searching,
|
||||
remote data sets, and pagination of results.
|
||||
|
||||
To get started, checkout examples and documentation at
|
||||
https://select2.org/
|
||||
|
||||
Use cases
|
||||
---------
|
||||
* Enhancing native selects with search.
|
||||
* Enhancing native selects with a better multi-select interface.
|
||||
* Loading data from JavaScript: easily load items via AJAX and have them
|
||||
searchable.
|
||||
* Nesting optgroups: native selects only support one level of nesting. Select2
|
||||
does not have this restriction.
|
||||
* Tagging: ability to add new items on the fly.
|
||||
* Working with large, remote datasets: ability to partially load a dataset based
|
||||
on the search term.
|
||||
* Paging of large datasets: easy support for loading more pages when the results
|
||||
are scrolled to the end.
|
||||
* Templating: support for custom rendering of results and selections.
|
||||
|
||||
Browser compatibility
|
||||
---------------------
|
||||
* IE 8+
|
||||
* Chrome 8+
|
||||
* Firefox 10+
|
||||
* Safari 3+
|
||||
* Opera 10.6+
|
||||
|
||||
Select2 is automatically tested on the following browsers.
|
||||
|
||||
[![Sauce Labs Test Status][saucelabs-matrix]][saucelabs-status]
|
||||
|
||||
Usage
|
||||
-----
|
||||
You can source Select2 directly from a CDN like [JSDliver][jsdelivr] or
|
||||
[CDNJS][cdnjs], [download it from this GitHub repo][releases], or use one of
|
||||
the integrations below.
|
||||
|
||||
Integrations
|
||||
------------
|
||||
Third party developers have created plugins for platforms which allow Select2 to be integrated more natively and quickly. For many platforms, additional plugins are not required because Select2 acts as a standard `<select>` box.
|
||||
|
||||
Plugins
|
||||
|
||||
* [Django]
|
||||
- [django-autocomplete-light]
|
||||
- [django-easy-select2]
|
||||
- [django-select2]
|
||||
* [Meteor] - [meteor-select2]
|
||||
* [Ruby on Rails][ruby-on-rails] - [select2-rails]
|
||||
* [Wicket] - [wicketstuff-select2]
|
||||
* [Yii 2][yii2] - [yii2-widget-select2]
|
||||
|
||||
Themes
|
||||
|
||||
- [Bootstrap 3][bootstrap3] - [select2-bootstrap-theme]
|
||||
- [Flat UI][flat-ui] - [select2-flat-theme]
|
||||
- [Metro UI][metro-ui] - [select2-metro]
|
||||
|
||||
Missing an integration? Modify this `README` and make a pull request back here to Select2 on GitHub.
|
||||
|
||||
Internationalization (i18n)
|
||||
---------------------------
|
||||
Select2 supports multiple languages by simply including the right language JS
|
||||
file (`dist/js/i18n/it.js`, `dist/js/i18n/nl.js`, etc.) after
|
||||
`dist/js/select2.js`.
|
||||
|
||||
Missing a language? Just copy `src/js/select2/i18n/en.js`, translate it, and
|
||||
make a pull request back to Select2 here on GitHub.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
The documentation for Select2 is available
|
||||
[through GitHub Pages][documentation] and is located within this repository
|
||||
in the [`docs` folder][documentation-folder].
|
||||
|
||||
Community
|
||||
---------
|
||||
You can find out about the different ways to get in touch with the Select2
|
||||
community at the [Select2 community page][community].
|
||||
|
||||
Copyright and license
|
||||
---------------------
|
||||
The license is available within the repository in the [LICENSE][license] file.
|
||||
|
||||
[cdnjs]: http://www.cdnjs.com/libraries/select2
|
||||
[community]: https://select2.org/getting-help
|
||||
[documentation]: https://select2.org
|
||||
[documentation-folder]: https://github.com/select2/select2/tree/master/docs
|
||||
[freenode]: https://freenode.net/
|
||||
[jsdelivr]: http://www.jsdelivr.com/#!select2
|
||||
[license]: LICENSE.md
|
||||
[releases]: https://github.com/select2/select2/releases
|
||||
[saucelabs-matrix]: https://saucelabs.com/browser-matrix/select2.svg
|
||||
[saucelabs-status]: https://saucelabs.com/u/select2
|
||||
[travis-ci-image]: https://img.shields.io/travis/select2/select2/master.svg
|
||||
[travis-ci-status]: https://travis-ci.org/select2/select2
|
||||
|
||||
[bootstrap3]: https://getbootstrap.com/
|
||||
[django]: https://www.djangoproject.com/
|
||||
[django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light
|
||||
[django-easy-select2]: https://github.com/asyncee/django-easy-select2
|
||||
[django-select2]: https://github.com/applegrew/django-select2
|
||||
[flat-ui]: http://designmodo.github.io/Flat-UI/
|
||||
[meteor]: https://www.meteor.com/
|
||||
[meteor-select2]: https://github.com/nate-strauser/meteor-select2
|
||||
[metro-ui]: http://metroui.org.ua/
|
||||
[select2-metro]: http://metroui.org.ua/select2.html
|
||||
[ruby-on-rails]: http://rubyonrails.org/
|
||||
[select2-bootstrap-theme]: https://github.com/select2/select2-bootstrap-theme
|
||||
[select2-flat-theme]: https://github.com/techhysahil/select2-Flat_Theme
|
||||
[select2-rails]: https://github.com/argerim/select2-rails
|
||||
[vue.js]: http://vuejs.org/
|
||||
[select2-vue]: http://vuejs.org/examples/select2.html
|
||||
[wicket]: https://wicket.apache.org/
|
||||
[wicketstuff-select2]: https://github.com/wicketstuff/core/tree/master/select2-parent
|
||||
[yii2]: http://www.yiiframework.com/
|
||||
[yii2-widget-select2]: https://github.com/kartik-v/yii2-widget-select2
|
||||
484
netbox/project-static/select2-4.0.5/css/select2.css
Executable file
484
netbox/project-static/select2-4.0.5/css/select2.css
Executable file
@@ -0,0 +1,484 @@
|
||||
.select2-container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
vertical-align: middle; }
|
||||
.select2-container .select2-selection--single {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 28px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||
display: block;
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-selection--single .select2-selection__clear {
|
||||
position: relative; }
|
||||
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 8px;
|
||||
padding-left: 20px; }
|
||||
.select2-container .select2-selection--multiple {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-search--inline {
|
||||
float: left; }
|
||||
.select2-container .select2-search--inline .select2-search__field {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
padding: 0; }
|
||||
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
|
||||
.select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
width: 100%;
|
||||
z-index: 1051; }
|
||||
|
||||
.select2-results {
|
||||
display: block; }
|
||||
|
||||
.select2-results__options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.select2-results__option {
|
||||
padding: 6px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-results__option[aria-selected] {
|
||||
cursor: pointer; }
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
left: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--below {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-search--dropdown {
|
||||
display: block;
|
||||
padding: 4px; }
|
||||
.select2-search--dropdown .select2-search__field {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
.select2-search--dropdown.select2-search--hide {
|
||||
display: none; }
|
||||
|
||||
.select2-close-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 99;
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0); }
|
||||
|
||||
.select2-hidden-accessible {
|
||||
border: 0 !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
height: 1px !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
width: 1px !important; }
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
background-color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
width: 100%; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
|
||||
list-style: none; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
float: left; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
float: right; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border: solid black 1px;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa; }
|
||||
|
||||
.select2-container--default .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: textfield; }
|
||||
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--default .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-disabled=true] {
|
||||
color: #999; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-selected=true] {
|
||||
background-color: #ddd; }
|
||||
|
||||
.select2-container--default .select2-results__option .select2-results__option {
|
||||
padding-left: 1em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -1em;
|
||||
padding-left: 2em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -2em;
|
||||
padding-left: 3em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -3em;
|
||||
padding-left: 4em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -4em;
|
||||
padding-left: 5em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -5em;
|
||||
padding-left: 6em; }
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #5897fb;
|
||||
color: white; }
|
||||
|
||||
.select2-container--default .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic .select2-selection--single {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-left: 1px solid #aaa;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
border: none;
|
||||
border-right: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||
background: transparent;
|
||||
border: none; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
|
||||
|
||||
.select2-container--classic .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-selection--multiple:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__rendered {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #555; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
float: right; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||
border: 1px solid #5897fb; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||
outline: 0;
|
||||
box-shadow: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--above {
|
||||
border-bottom: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--below {
|
||||
border-top: none; }
|
||||
|
||||
.select2-container--classic .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--classic .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--classic .select2-results__option[aria-disabled=true] {
|
||||
color: grey; }
|
||||
|
||||
.select2-container--classic .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #3875d7;
|
||||
color: white; }
|
||||
|
||||
.select2-container--classic .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb; }
|
||||
1
netbox/project-static/select2-4.0.5/css/select2.min.css
vendored
Executable file
1
netbox/project-static/select2-4.0.5/css/select2.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
3
netbox/project-static/select2-4.0.5/js/i18n/af.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/af.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Verwyders asseblief "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Voer asseblief "+t+" of meer karakters";return n},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var t="Kies asseblief net "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ar.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ar.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(e){var t=e.input.length-e.maximum;return"الرجاء حذف "+t+" عناصر"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"الرجاء إضافة "+t+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(e){return"تستطيع إختيار "+e.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/az.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/az.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/bg.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/bg.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/bs.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/bs.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bs",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ca.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ca.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/cs.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/cs.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadejte o jeden znak méně.":n<=4?"Prosím, zadejte o "+e(n,!0)+" znaky méně.":"Prosím, zadejte o "+n+" znaků méně."},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadejte ještě jeden znak.":n<=4?"Prosím, zadejte ještě další "+e(n,!0)+" znaky.":"Prosím, zadejte ještě dalších "+n+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku.":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky.":"Můžete zvolit maximálně "+n+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/da.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/da.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Angiv venligst "+t+" tegn mindre"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Angiv venligst "+t+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/de.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/de.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/dsb.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/dsb.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/dsb",[],function(){var e=["znamuško","znamušce","znamuška","znamuškow"],t=["zapisk","zapiska","zapiski","zapiskow"],n=function(t,n){if(t===1)return n[0];if(t===2)return n[1];if(t>2&&t<=4)return n[2];if(t>=5)return n[3]};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Pšosym lašuj "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Pšosym zapódaj nanejmjenjej "+r+" "+n(r,e)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(e){return"Móžoš jano "+e.maximum+" "+n(e.maximum,t)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/el.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/el.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Παρακαλώ διαγράψτε "+t+" χαρακτήρ";return t==1&&(n+="α"),t!=1&&(n+="ες"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Παρακαλώ συμπληρώστε "+t+" ή περισσότερους χαρακτήρες";return n},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(e){var t="Μπορείτε να επιλέξετε μόνο "+e.maximum+" επιλογ";return e.maximum==1&&(t+="ή"),e.maximum!=1&&(t+="ές"),t},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/en.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/en.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/es.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/es.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/et.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/et.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/eu.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/eu.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/fa.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/fa.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/fi.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/fi.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/fr.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/fr.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Supprimez "+t+" caractère"+(t>1)?"s":""},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Saisissez au moins "+t+" caractère"+(t>1)?"s":""},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1)?"s":""},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/gl.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/gl.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var t=e.input.length-e.maximum;return t===1?"Elimine un carácter":"Elimine "+t+" caracteres"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t===1?"Engada un carácter":"Engada "+t+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return e.maximum===1?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/he.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/he.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/hi.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/hi.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/hr.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/hr.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/hsb.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/hsb.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hsb",[],function(){var e=["znamješko","znamješce","znamješka","znamješkow"],t=["zapisk","zapiskaj","zapiski","zapiskow"],n=function(t,n){if(t===1)return n[0];if(t===2)return n[1];if(t>2&&t<=4)return n[2];if(t>=5)return n[3]};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Prošu zhašej "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Prošu zapodaj znajmjeńša "+r+" "+n(r,e)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(e){return"Móžeš jenož "+e.maximum+" "+n(e.maximum,t)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/hu.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/hu.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/hy.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/hy.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Խնդրում ենք հեռացնել "+t+" նշան";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Խնդրում ենք մուտքագրել "+t+" կամ ավել նշաններ";return n},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(e){var t="Դուք կարող եք ընտրել առավելագույնը "+e.maximum+" կետ";return t},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/id.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/id.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/is.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/is.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/it.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/it.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ja.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ja.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/km.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/km.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="សូមលុបចេញ "+t+" អក្សរ";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="សូមបញ្ចូល"+t+" អក្សរ រឺ ច្រើនជាងនេះ";return n},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(e){var t="អ្នកអាចជ្រើសរើសបានតែ "+e.maximum+" ជម្រើសប៉ុណ្ណោះ";return t},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ko.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ko.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/lt.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/lt.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%10===1&&(e%100<11||e%100>19)?t:e%10>=2&&e%10<=9&&(e%100<11||e%100>19)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"į","ius","ių"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"į","ius","ių"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ą","us","ų"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/lv.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/lv.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/mk.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/mk.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ms.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ms.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/nb.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/nb.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn "+t+" tegn til";return n+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/nl.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/nl.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/pl.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/pl.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ps.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ps.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="د مهربانۍ لمخي "+t+" توری ړنګ کړئ";return t!=1&&(n=n.replace("توری","توري")),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لږ تر لږه "+t+" يا ډېر توري وليکئ";return n},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(e){var t="تاسو يوازي "+e.maximum+" قلم په نښه کولای سی";return e.maximum!=1&&(t=t.replace("قلم","قلمونه")),t},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/pt-BR.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/pt-BR.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/pt.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/pt.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"caractere",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ro.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ro.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return t!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți "+t+" sau mai multe caractere";return n},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",e.maximum!==1&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/ru.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/ru.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/sk.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/sk.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/sl.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/sl.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Prosim zbrišite "+t+" znak";return t==2?n+="a":t!=1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Prosim vpišite še "+t+" znak";return t==2?n+="a":t!=1&&(n+="e"),n},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var t="Označite lahko največ "+e.maximum+" predmet";return e.maximum==2?t+="a":e.maximum!=1&&(t+="e"),t},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/sr-Cyrl.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/sr-Cyrl.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/sr.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/sr.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/sv.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/sv.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/th.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/th.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/tr.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/tr.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/uk.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/uk.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/vi.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/vi.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+" ký tự";return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/zh-CN.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/zh-CN.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})();
|
||||
3
netbox/project-static/select2-4.0.5/js/i18n/zh-TW.js
Executable file
3
netbox/project-static/select2-4.0.5/js/i18n/zh-TW.js
Executable file
@@ -0,0 +1,3 @@
|
||||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})();
|
||||
6457
netbox/project-static/select2-4.0.5/js/select2.full.js
Executable file
6457
netbox/project-static/select2-4.0.5/js/select2.full.js
Executable file
File diff suppressed because it is too large
Load Diff
1
netbox/project-static/select2-4.0.5/js/select2.full.min.js
vendored
Executable file
1
netbox/project-static/select2-4.0.5/js/select2.full.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
5746
netbox/project-static/select2-4.0.5/js/select2.js
Executable file
5746
netbox/project-static/select2-4.0.5/js/select2.js
Executable file
File diff suppressed because it is too large
Load Diff
1
netbox/project-static/select2-4.0.5/js/select2.min.js
vendored
Executable file
1
netbox/project-static/select2-4.0.5/js/select2.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
7
netbox/project-static/select2-bootstrap-0.1.0-beta.10/select2-bootstrap.min.css
vendored
Normal file
7
netbox/project-static/select2-bootstrap-0.1.0-beta.10/select2-bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -3,11 +3,11 @@ from django.db.models import Q
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from utilities.filters import NumericInFilter, TagFilter
|
||||
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
||||
from .models import Secret, SecretRole
|
||||
|
||||
|
||||
class SecretRoleFilter(django_filters.FilterSet):
|
||||
class SecretRoleFilter(NameSlugSearchFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = SecretRole
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from Crypto.Cipher import PKCS1_OAEP
|
||||
from Crypto.PublicKey import RSA
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldForm
|
||||
from utilities.forms import BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField
|
||||
from utilities.forms import (
|
||||
APISelect, APISelectMultiple, BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField,
|
||||
StaticSelect2Multiple
|
||||
)
|
||||
from .models import Secret, SecretRole, UserKey
|
||||
|
||||
|
||||
@@ -42,6 +44,10 @@ class SecretRoleForm(BootstrapMixin, forms.ModelForm):
|
||||
fields = [
|
||||
'name', 'slug', 'users', 'groups',
|
||||
]
|
||||
widgets = {
|
||||
'users': StaticSelect2Multiple(),
|
||||
'groups': StaticSelect2Multiple(),
|
||||
}
|
||||
|
||||
|
||||
class SecretRoleCSVForm(forms.ModelForm):
|
||||
@@ -85,6 +91,11 @@ class SecretForm(BootstrapMixin, CustomFieldForm):
|
||||
fields = [
|
||||
'role', 'name', 'plaintext', 'plaintext2', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'role': APISelect(
|
||||
api_url="/api/secrets/secret-roles/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -143,7 +154,10 @@ class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=SecretRole.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/secrets/secret-roles/"
|
||||
)
|
||||
)
|
||||
name = forms.CharField(
|
||||
max_length=100,
|
||||
@@ -163,10 +177,12 @@ class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
label='Search'
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=SecretRole.objects.annotate(
|
||||
filter_count=Count('secrets')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=SecretRole.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/secrets/secret-roles/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'font-awesome-4.7.0/css/font-awesome.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'jquery-ui-1.12.1/jquery-ui.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'select2-4.0.5/css/select2.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'select2-bootstrap-0.1.0-beta.10/select2-bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/base.css' %}?v{{ settings.VERSION }}">
|
||||
<link rel="icon" type="image/png" href="{% static 'img/netbox.ico' %}" />
|
||||
<meta charset="UTF-8">
|
||||
@@ -66,6 +68,7 @@
|
||||
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
|
||||
<script src="{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}"></script>
|
||||
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'select2-4.0.5/js/select2.min.js' %}"></script>
|
||||
<script src="{% static 'js/forms.js' %}?v{{ settings.VERSION }}"></script>
|
||||
<script type="text/javascript">
|
||||
var netbox_api_path = "/{{ settings.BASE_PATH }}api/";
|
||||
|
||||
@@ -107,14 +107,14 @@
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="search">
|
||||
{% render_field form.livesearch %}
|
||||
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
{% render_field form.termination_b_site %}
|
||||
{% render_field form.termination_b_rack %}
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.termination_b_device %}
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.termination_b_type %}
|
||||
{% render_field form.termination_b_id %}
|
||||
</div>
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
{% if cable.label %}<code>{{ cable.label }}</code>{% else %}Cable #{{ cable.pk }}{% endif %}
|
||||
</a>
|
||||
</h4>
|
||||
{{ cable.get_status_display }}<br />
|
||||
{{ cable.get_type_display|default:"" }}
|
||||
<p><span class="label label-{% if cable.status %}success{% else %}info{% endif %}">{{ cable.get_status_display }}</span></p>
|
||||
<p>{{ cable.get_type_display|default:"" }}</p>
|
||||
{% if cable.length %}- {{ cable.length }}{{ cable.get_length_unit_display }}{% endif %}
|
||||
<span class="label color-block center-block" style="background-color: #{{ cable.color }}"> </span>
|
||||
{% else %}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
{% include 'responsive_table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
{% include 'inc/search_panel.html' %}
|
||||
|
||||
@@ -682,7 +682,8 @@
|
||||
<th>Rear Port</th>
|
||||
<th>Position</th>
|
||||
<th>Description</th>
|
||||
<th>Connected Cable</th>
|
||||
<th>Cable</th>
|
||||
<th colspan="2">Connection</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -735,7 +736,8 @@
|
||||
<th>Type</th>
|
||||
<th>Positions</th>
|
||||
<th>Description</th>
|
||||
<th>Connected Cable</th>
|
||||
<th>Cable</th>
|
||||
<th colspan="2">Connection</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -20,88 +20,3 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
var site_list = $('#id_site');
|
||||
var rack_group_list = $('#id_rack_group_id');
|
||||
var rack_list = $('#id_rack_id');
|
||||
var manufacturer_list = $('#id_manufacturer_id');
|
||||
var model_list = $('#id_device_type_id');
|
||||
|
||||
// Update device type options based on selected manufacturer
|
||||
manufacturer_list.change(function() {
|
||||
var selected_manufacturers = $(this).val();
|
||||
if (selected_manufacturers) {
|
||||
model_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/device-types/?limit=500&manufacturer_id=' + selected_manufacturers.join('&manufacturer_id='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, device_type) {
|
||||
var option = $("<option></option>").attr("value", device_type.id).text(device_type.model + " (" + device_type.instance_count + ")");
|
||||
model_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack group and rack options based on selected site
|
||||
site_list.change(function() {
|
||||
var selected_sites = $(this).val();
|
||||
if (selected_sites) {
|
||||
|
||||
// Update rack group options
|
||||
rack_group_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/rack-groups/?limit=500&site=' + selected_sites.join('&site='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, group) {
|
||||
var option = $("<option></option>").attr("value", group.id).text(group.name);
|
||||
rack_group_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack options
|
||||
rack_list.empty();
|
||||
rack_list.append($("<option></option>").attr("value", "0").text("None"));
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/racks/?limit=500&site=' + selected_sites.join('&site='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, rack) {
|
||||
var option = $("<option></option>").attr("value", rack.id).text(rack.display_name);
|
||||
rack_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack options based on selected rack group
|
||||
rack_group_list.change(function() {
|
||||
var selected_rack_groups = $(this).val();
|
||||
if (selected_rack_groups) {
|
||||
rack_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/racks/?limit=500&group_id=' + selected_rack_groups.join('&group_id='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, rack) {
|
||||
var option = $("<option></option>").attr("value", rack.id).text(rack.display_name);
|
||||
rack_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -73,6 +73,7 @@ $(document).ready(function() {
|
||||
url: "{% url 'dcim-api:device-napalm' pk=device.pk %}?method=get_facts&method=get_environment",
|
||||
dataType: 'json',
|
||||
success: function(json) {
|
||||
if (!json['get_facts']['error']) {
|
||||
$('#hostname').html(json['get_facts']['hostname']);
|
||||
$('#fqdn').html(json['get_facts']['fqdn']);
|
||||
$('#vendor').html(json['get_facts']['vendor']);
|
||||
@@ -86,6 +87,9 @@ $(document).ready(function() {
|
||||
var uptime_hours = Math.floor(uptime % 86400 / 3600);
|
||||
var uptime_minutes = Math.floor(uptime % 3600 / 60);
|
||||
$('#uptime').html(uptime_days + "d " + uptime_hours + "h " + uptime_minutes + "m");
|
||||
}
|
||||
|
||||
if (!json['get_environment']['error']) {
|
||||
$.each(json['get_environment']['cpu'], function(name, obj) {
|
||||
var row="<tr><td>" + name + "</td><td>" + obj['%usage'] + "%</td></tr>";
|
||||
$("#cpu").after(row)
|
||||
@@ -120,6 +124,7 @@ $(document).ready(function() {
|
||||
}
|
||||
$("#power").after(row)
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert(xhr.responseText);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user