nautobot 2.4.2__py3-none-any.whl → 2.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/filters.py +2 -0
- nautobot/circuits/filters.py +1 -1
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +1 -1
- nautobot/circuits/tests/integration/test_circuit.py +135 -0
- nautobot/circuits/tests/test_models.py +5 -3
- nautobot/circuits/views.py +4 -1
- nautobot/cloud/api/views.py +3 -3
- nautobot/cloud/filters.py +3 -6
- nautobot/cloud/tests/test_filters.py +21 -0
- nautobot/core/admin.py +2 -0
- nautobot/core/constants.py +0 -1
- nautobot/core/forms/__init__.py +2 -0
- nautobot/core/forms/forms.py +2 -1
- nautobot/core/forms/widgets.py +8 -0
- nautobot/core/jobs/__init__.py +2 -1
- nautobot/core/management/commands/generate_performance_test_endpoints.py +271 -0
- nautobot/core/models/utils.py +6 -1
- nautobot/core/templates/generic/object_bulk_delete.html +1 -1
- nautobot/core/templates/generic/object_bulk_edit.html +1 -1
- nautobot/core/templates/generic/object_bulk_import.html +1 -1
- nautobot/core/templates/generic/object_create.html +5 -0
- nautobot/core/templates/generic/object_delete.html +1 -1
- nautobot/core/templates/generic/object_detail.html +1 -1
- nautobot/core/templates/generic/object_edit.html +1 -1
- nautobot/core/templates/inc/javascript.html +3 -0
- nautobot/core/templates/widgets/clearable_file.html +5 -0
- nautobot/core/templatetags/helpers.py +3 -3
- nautobot/core/templatetags/ui_framework.py +20 -4
- nautobot/core/testing/forms.py +1 -1
- nautobot/core/testing/integration.py +37 -7
- nautobot/core/tests/test_api.py +1 -1
- nautobot/core/tests/test_commands.py +31 -0
- nautobot/core/tests/test_graphql.py +3 -3
- nautobot/core/tests/test_jobs.py +4 -1
- nautobot/core/tests/test_utils.py +17 -2
- nautobot/core/ui/object_detail.py +1 -1
- nautobot/core/utils/lookup.py +12 -1
- nautobot/core/views/generic.py +9 -1
- nautobot/core/views/mixins.py +9 -1
- nautobot/dcim/api/serializers.py +36 -0
- nautobot/dcim/api/views.py +12 -11
- nautobot/dcim/elevations.py +17 -4
- nautobot/dcim/factory.py +9 -1
- nautobot/dcim/filters/__init__.py +27 -1
- nautobot/dcim/forms.py +16 -7
- nautobot/dcim/models/devices.py +12 -7
- nautobot/dcim/signals.py +26 -0
- nautobot/dcim/templates/dcim/cable_trace.html +4 -4
- nautobot/dcim/templates/dcim/consoleport.html +14 -4
- nautobot/dcim/templates/dcim/consoleserverport.html +14 -4
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +3 -3
- nautobot/dcim/templates/dcim/frontport.html +7 -2
- nautobot/dcim/templates/dcim/interface.html +9 -4
- nautobot/dcim/templates/dcim/powerfeed.html +8 -3
- nautobot/dcim/templates/dcim/poweroutlet.html +14 -4
- nautobot/dcim/templates/dcim/powerport.html +14 -4
- nautobot/dcim/templates/dcim/rearport.html +7 -2
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -62
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +6 -0
- nautobot/dcim/tests/integration/test_fileinputpicker.py +87 -0
- nautobot/dcim/tests/test_api.py +176 -0
- nautobot/dcim/tests/test_filters.py +56 -3
- nautobot/dcim/tests/test_models.py +41 -1
- nautobot/dcim/views.py +24 -14
- nautobot/extras/api/mixins.py +1 -1
- nautobot/extras/api/views.py +4 -4
- nautobot/extras/filters/__init__.py +4 -0
- nautobot/extras/forms/forms.py +4 -0
- nautobot/extras/jobs.py +8 -1
- nautobot/extras/models/datasources.py +7 -3
- nautobot/extras/plugins/__init__.py +26 -1
- nautobot/extras/templates/extras/inc/jobresult.html +12 -13
- nautobot/extras/templates/extras/job.html +1 -0
- nautobot/extras/templates/extras/objectchange.html +28 -12
- nautobot/extras/tests/test_api.py +16 -15
- nautobot/extras/tests/test_dynamicgroups.py +14 -0
- nautobot/extras/tests/test_filters.py +2 -0
- nautobot/extras/tests/test_plugins.py +32 -1
- nautobot/extras/tests/test_views.py +209 -11
- nautobot/extras/utils.py +30 -0
- nautobot/extras/views.py +32 -14
- nautobot/ipam/api/serializers.py +7 -8
- nautobot/ipam/api/views.py +5 -5
- nautobot/ipam/factory.py +27 -8
- nautobot/ipam/filters.py +67 -29
- nautobot/ipam/formfields.py +51 -0
- nautobot/ipam/forms.py +15 -7
- nautobot/ipam/migrations/0051_added_optional_vrf_relationship_to_vdc.py +41 -0
- nautobot/ipam/models.py +63 -5
- nautobot/ipam/tables.py +21 -7
- nautobot/ipam/tests/test_api.py +107 -66
- nautobot/ipam/tests/test_filters.py +145 -5
- nautobot/ipam/tests/test_views.py +15 -2
- nautobot/project-static/bootstrap-filestyle-1.2.3/bootstrap-filestyle.min.js +11 -0
- nautobot/project-static/css/base.css +11 -0
- nautobot/project-static/css/dark.css +2 -1
- nautobot/project-static/docs/apps/index.html +1 -1
- nautobot/project-static/docs/apps/nautobot-apps.html +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +62 -0
- nautobot/project-static/docs/development/apps/api/configuration-view.html +0 -3
- nautobot/project-static/docs/development/apps/api/models/graphql.html +9 -13
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +94 -1
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +2 -5
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +0 -3
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +0 -3
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +0 -3
- nautobot/project-static/docs/development/apps/api/prometheus.html +0 -3
- nautobot/project-static/docs/development/apps/api/setup.html +1 -1
- nautobot/project-static/docs/development/apps/api/testing.html +0 -6
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +0 -3
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +0 -3
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +0 -3
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +0 -3
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +1 -7
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +0 -7
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +0 -4
- nautobot/project-static/docs/development/apps/api/views/notes.html +0 -3
- nautobot/project-static/docs/development/apps/index.html +2 -35
- nautobot/project-static/docs/development/apps/migration/code-updates.html +7 -6
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +2 -2
- nautobot/project-static/docs/development/apps/migration/from-v1.html +3 -3
- nautobot/project-static/docs/development/core/application-registry.html +0 -6
- nautobot/project-static/docs/development/core/best-practices.html +1 -28
- nautobot/project-static/docs/development/core/bootstrap-ui.html +1 -1
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +65 -11
- nautobot/project-static/docs/development/core/getting-started.html +14 -18
- nautobot/project-static/docs/development/core/homepage.html +0 -3
- nautobot/project-static/docs/development/core/index.html +1 -1
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +3 -3
- nautobot/project-static/docs/development/core/model-checklist.html +1 -1
- nautobot/project-static/docs/development/core/navigation-menu.html +1 -1
- nautobot/project-static/docs/development/core/release-checklist.html +1 -1
- nautobot/project-static/docs/development/core/settings.html +1 -1
- nautobot/project-static/docs/development/core/style-guide.html +4 -9
- nautobot/project-static/docs/development/core/templates.html +0 -3
- nautobot/project-static/docs/development/core/testing.html +0 -9
- nautobot/project-static/docs/development/jobs/index.html +11 -30
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +3 -2
- nautobot/project-static/docs/index.html +3 -2
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +2 -20
- nautobot/project-static/docs/release-notes/version-1.0.html +2 -2
- nautobot/project-static/docs/release-notes/version-1.1.html +2 -2
- nautobot/project-static/docs/release-notes/version-1.2.html +3 -3
- nautobot/project-static/docs/release-notes/version-1.3.html +1 -1
- nautobot/project-static/docs/release-notes/version-1.4.html +17 -17
- nautobot/project-static/docs/release-notes/version-1.5.html +8 -8
- nautobot/project-static/docs/release-notes/version-1.6.html +4 -4
- nautobot/project-static/docs/release-notes/version-2.0.html +10 -10
- nautobot/project-static/docs/release-notes/version-2.1.html +7 -7
- nautobot/project-static/docs/release-notes/version-2.2.html +1 -1
- nautobot/project-static/docs/release-notes/version-2.3.html +4 -4
- nautobot/project-static/docs/release-notes/version-2.4.html +379 -0
- nautobot/project-static/docs/requirements.txt +1 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +290 -290
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +3 -3
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +4 -4
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +1 -1
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +3 -13
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +5 -5
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +3 -18
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +1 -1
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +4 -4
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +15 -15
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +2 -2
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +1 -1
- nautobot/project-static/docs/user-guide/administration/installation/index.html +0 -16
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +1 -1
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +7 -10
- nautobot/project-static/docs/user-guide/administration/installation/services.html +1 -12
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +3 -3
- nautobot/project-static/docs/user-guide/administration/security/index.html +1 -1
- nautobot/project-static/docs/user-guide/administration/security/notices.html +1 -0
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +5 -35
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +1 -1
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-location-changes.yaml +1 -1
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +12 -9
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +0 -3
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +0 -3
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +1 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +0 -3
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +0 -3
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +1 -7
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +0 -6
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +0 -3
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +0 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +0 -8
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +15 -15
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -1
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +0 -6
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +0 -3
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +3 -15
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1 -27
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +0 -8
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +3 -6
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +0 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +0 -7
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +0 -3
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +0 -3
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +2 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +6 -6
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +0 -14
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +0 -3
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +1 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +0 -3
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +0 -14
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +0 -19
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +3 -9
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +0 -8
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +0 -4
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +1 -13
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +0 -5
- nautobot/project-static/js/dropdown.js +28 -0
- nautobot/project-static/js/editor.js +292 -0
- nautobot/project-static/monaco-editor-0.52.2/README.md +81 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/base/worker/workerMain.js +31 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/basic-languages/xml/xml.js +10 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/basic-languages/yaml/yaml.js +10 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/editor/editor.main.css +8 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/editor/editor.main.js +798 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/language/json/jsonMode.js +19 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/language/json/jsonWorker.js +42 -0
- nautobot/project-static/monaco-editor-0.52.2/vs/loader.js +11 -0
- nautobot/tenancy/filters/__init__.py +3 -5
- nautobot/tenancy/forms.py +9 -0
- nautobot/tenancy/templates/tenancy/tenant_create.html +21 -0
- nautobot/tenancy/templates/tenancy/tenant_edit.html +2 -21
- nautobot/tenancy/templates/tenancy/tenantgroup.html +2 -44
- nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +1 -0
- nautobot/tenancy/tests/test_filters.py +10 -0
- nautobot/tenancy/tests/test_views.py +5 -1
- nautobot/tenancy/urls.py +7 -79
- nautobot/tenancy/views.py +51 -80
- nautobot/virtualization/views.py +0 -1
- nautobot/wireless/api/serializers.py +6 -1
- nautobot/wireless/api/views.py +3 -3
- nautobot/wireless/tables.py +9 -4
- nautobot/wireless/tests/test_api.py +5 -9
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/METADATA +9 -9
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/RECORD +267 -246
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/NOTICE +0 -0
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/WHEEL +0 -0
- {nautobot-2.4.2.dist-info → nautobot-2.4.4.dist-info}/entry_points.txt +0 -0
nautobot/apps/filters.py
CHANGED
|
@@ -43,6 +43,7 @@ from nautobot.extras.filters.mixins import (
|
|
|
43
43
|
StatusFilter,
|
|
44
44
|
)
|
|
45
45
|
from nautobot.extras.plugins import FilterExtension
|
|
46
|
+
from nautobot.ipam.filters import PrefixFilter
|
|
46
47
|
from nautobot.tenancy.filters import TenancyModelFilterSetMixin
|
|
47
48
|
|
|
48
49
|
__all__ = (
|
|
@@ -72,6 +73,7 @@ __all__ = (
|
|
|
72
73
|
"NaturalKeyOrPKMultipleChoiceFilter",
|
|
73
74
|
"NautobotFilterSet",
|
|
74
75
|
"NumericArrayFilter",
|
|
76
|
+
"PrefixFilter",
|
|
75
77
|
"RelatedMembershipBooleanFilter",
|
|
76
78
|
"RelationshipFilter",
|
|
77
79
|
"RelationshipModelFilterSetMixin",
|
nautobot/circuits/filters.py
CHANGED
|
@@ -16,7 +16,7 @@ from nautobot.dcim.filters import (
|
|
|
16
16
|
)
|
|
17
17
|
from nautobot.dcim.models import Location
|
|
18
18
|
from nautobot.extras.filters import NautobotFilterSet, StatusModelFilterSetMixin
|
|
19
|
-
from nautobot.tenancy.filters import TenancyModelFilterSetMixin
|
|
19
|
+
from nautobot.tenancy.filters.mixins import TenancyModelFilterSetMixin
|
|
20
20
|
|
|
21
21
|
from .models import Circuit, CircuitTermination, CircuitType, Provider, ProviderNetwork
|
|
22
22
|
|
|
@@ -6,7 +6,7 @@ In a future release, we should delete this file.
|
|
|
6
6
|
|
|
7
7
|
<div class="panel panel-default">
|
|
8
8
|
<div class="panel-heading">
|
|
9
|
-
{% include 'circuits/inc/circuit_termination_header_extra_content.html' with termination=termination %}
|
|
9
|
+
{% include 'circuits/inc/circuit_termination_header_extra_content.html' with termination=termination side=side %}
|
|
10
10
|
<strong>Termination - {{ side }} Side</strong>
|
|
11
11
|
</div>
|
|
12
12
|
{% if termination %}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from django.contrib.contenttypes.models import ContentType
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
|
|
4
|
+
from nautobot.circuits.models import Circuit, CircuitTermination, CircuitType, Provider
|
|
5
|
+
from nautobot.core.testing.integration import ObjectDetailsMixin, ObjectsListMixin, SeleniumTestCase
|
|
6
|
+
from nautobot.dcim.models import Location, LocationType
|
|
7
|
+
from nautobot.extras.models import Status
|
|
8
|
+
from nautobot.tenancy.models import Tenant, TenantGroup
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CircuitTestCase(SeleniumTestCase, ObjectsListMixin, ObjectDetailsMixin):
|
|
12
|
+
"""
|
|
13
|
+
Integration test to check circuits related test cases.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def setUp(self):
|
|
17
|
+
super().setUp()
|
|
18
|
+
self.login_as_superuser()
|
|
19
|
+
|
|
20
|
+
# Termination requirements
|
|
21
|
+
location_type, location_created = LocationType.objects.get_or_create(name="Circuit at Home")
|
|
22
|
+
if location_created:
|
|
23
|
+
location_ct = ContentType.objects.get_for_model(CircuitTermination)
|
|
24
|
+
location_type.content_types.set([location_ct])
|
|
25
|
+
location_type.save()
|
|
26
|
+
|
|
27
|
+
location_status = Status.objects.get_for_model(Location).first()
|
|
28
|
+
self.location, _ = Location.objects.get_or_create(
|
|
29
|
+
name="A Test Location",
|
|
30
|
+
status=location_status,
|
|
31
|
+
location_type=location_type,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
self.provider, _ = Provider.objects.get_or_create(name="World Best Cables")
|
|
35
|
+
self.circuit_type, _ = CircuitType.objects.get_or_create(
|
|
36
|
+
name="Yellow Cable",
|
|
37
|
+
)
|
|
38
|
+
self.tenant_group, _ = TenantGroup.objects.get_or_create(name="Family Inc.")
|
|
39
|
+
self.tenant, _ = Tenant.objects.get_or_create(name="Tenant 1", tenant_group=self.tenant_group)
|
|
40
|
+
|
|
41
|
+
def create_circuit(self, name):
|
|
42
|
+
circuit, _ = Circuit.objects.get_or_create(
|
|
43
|
+
provider=self.provider,
|
|
44
|
+
cid=name,
|
|
45
|
+
circuit_type=self.circuit_type,
|
|
46
|
+
status=Status.objects.get_for_model(Circuit).first(),
|
|
47
|
+
)
|
|
48
|
+
return circuit
|
|
49
|
+
|
|
50
|
+
def test_circuit_create(self):
|
|
51
|
+
cid = "Circuit-test-abc123"
|
|
52
|
+
description = "My Precious Circuit"
|
|
53
|
+
|
|
54
|
+
# Create new Circuit from list view
|
|
55
|
+
self.click_navbar_entry("Circuits", "Circuits")
|
|
56
|
+
self.assertEqual(self.browser.url, self.live_server_url + reverse("circuits:circuit_list"))
|
|
57
|
+
|
|
58
|
+
self.click_list_view_add_button()
|
|
59
|
+
self.assertEqual(self.browser.url, self.live_server_url + reverse("circuits:circuit_add"))
|
|
60
|
+
|
|
61
|
+
# Fill Circuit creation form
|
|
62
|
+
self.fill_select2_field("provider", self.provider.name)
|
|
63
|
+
self.browser.fill("cid", cid)
|
|
64
|
+
self.fill_select2_field("circuit_type", self.circuit_type.name)
|
|
65
|
+
self.fill_select2_field("status", "") # pick first status
|
|
66
|
+
self.browser.fill("install_date", "2025-01-01")
|
|
67
|
+
self.browser.fill("commit_rate", 192)
|
|
68
|
+
self.browser.fill("description", "My Precious Circuit")
|
|
69
|
+
self.fill_select2_field("tenant_group", "Family Inc.")
|
|
70
|
+
self.fill_select2_field("tenant", "Tenant 1")
|
|
71
|
+
|
|
72
|
+
self.click_edit_form_create_button()
|
|
73
|
+
self.assertTrue(self.browser.is_text_present("Created circuit Circuit-test-abc123"))
|
|
74
|
+
|
|
75
|
+
# Navigate to Circuit details by filtering the one just created and clicking on it
|
|
76
|
+
self.click_navbar_entry("Circuits", "Circuits")
|
|
77
|
+
self.assertEqual(self.browser.url, self.live_server_url + reverse("circuits:circuit_list"))
|
|
78
|
+
|
|
79
|
+
self.apply_filter("circuit_type", "Yellow Cable")
|
|
80
|
+
self.assertEqual(self.objects_list_visible_items, 1)
|
|
81
|
+
|
|
82
|
+
self.click_table_link()
|
|
83
|
+
|
|
84
|
+
# Assert that value are properly set
|
|
85
|
+
circuit = Circuit.objects.get(cid=cid)
|
|
86
|
+
self.assertIn(self.live_server_url + reverse("circuits:circuit", kwargs={"pk": circuit.pk}), self.browser.url)
|
|
87
|
+
|
|
88
|
+
self.assertPanelValue("Circuit", "Circuit ID", cid)
|
|
89
|
+
self.assertPanelValue("Circuit", "Status", "Active")
|
|
90
|
+
self.assertPanelValue("Circuit", "Provider", self.provider.name)
|
|
91
|
+
self.assertPanelValue("Circuit", "Circuit Type", self.circuit_type.name)
|
|
92
|
+
self.assertPanelValue("Circuit", "Tenant", self.tenant.name)
|
|
93
|
+
self.assertPanelValue("Circuit", "Date Installed", "Jan. 1, 2025")
|
|
94
|
+
self.assertPanelValue("Circuit", "Commit Rate (Kbps)", "192")
|
|
95
|
+
self.assertPanelValue("Circuit", "Description", description)
|
|
96
|
+
|
|
97
|
+
def test_circuit_create_termination(self):
|
|
98
|
+
circuit = self.create_circuit("Circuit-test-termination")
|
|
99
|
+
sides = ["A", "Z"]
|
|
100
|
+
for side in sides:
|
|
101
|
+
with self.subTest(side=side):
|
|
102
|
+
# Go to Circuit details page
|
|
103
|
+
details_url = self.live_server_url + reverse("circuits:circuit", kwargs={"pk": circuit.pk})
|
|
104
|
+
self.browser.visit(details_url)
|
|
105
|
+
self.assertIn(details_url, self.browser.url)
|
|
106
|
+
|
|
107
|
+
# Find and click add termination button
|
|
108
|
+
termination_panel_xpath = f'//*[@id="main"]//div[@class="panel-heading"][contains(normalize-space(), "Termination - {side} Side")]'
|
|
109
|
+
self.browser.find_by_xpath(f'{termination_panel_xpath}//a[normalize-space()="Add"]').click()
|
|
110
|
+
|
|
111
|
+
port_speed = ord(side)
|
|
112
|
+
upstream_speed = ord(side) + 10
|
|
113
|
+
xconnect_id = f"xconnect-id-{side}-123"
|
|
114
|
+
pp_info = f"pp-info-{side}-123"
|
|
115
|
+
description = f"{side}-side"
|
|
116
|
+
|
|
117
|
+
# Fill termination creation form
|
|
118
|
+
self.fill_select2_field("location", self.location.name)
|
|
119
|
+
self.browser.fill("port_speed", port_speed)
|
|
120
|
+
self.browser.fill("upstream_speed", upstream_speed)
|
|
121
|
+
self.browser.fill("xconnect_id", xconnect_id)
|
|
122
|
+
self.browser.fill("pp_info", pp_info)
|
|
123
|
+
self.browser.fill("description", description)
|
|
124
|
+
self.click_edit_form_create_button()
|
|
125
|
+
|
|
126
|
+
self.assertTrue(self.browser.is_text_present(f"Created circuit termination Termination {side}"))
|
|
127
|
+
|
|
128
|
+
# Assert that value are properly set
|
|
129
|
+
panel_label = f"Termination - {side} Side"
|
|
130
|
+
self.assertPanelValue(panel_label, "Location", self.location.name)
|
|
131
|
+
self.assertPanelValue(panel_label, "Port Speed (Kbps)", port_speed)
|
|
132
|
+
self.assertPanelValue(panel_label, "Upstream Speed (Kbps)", upstream_speed)
|
|
133
|
+
self.assertPanelValue(panel_label, "Cross-connect ID", xconnect_id)
|
|
134
|
+
self.assertPanelValue(panel_label, "Patch Panel/port(s)", pp_info)
|
|
135
|
+
self.assertPanelValue(panel_label, "Description", description)
|
|
@@ -17,8 +17,7 @@ class CircuitTerminationModelTestCase(ModelTestCases.BaseModelTestCase):
|
|
|
17
17
|
provider = Provider.objects.first()
|
|
18
18
|
circuit_type = CircuitType.objects.first()
|
|
19
19
|
|
|
20
|
-
location_type_1 = LocationType.objects.
|
|
21
|
-
location_type_1.content_types.set([])
|
|
20
|
+
location_type_1 = LocationType.objects.create(name="University")
|
|
22
21
|
location_type_2 = LocationType.objects.get(name="Building")
|
|
23
22
|
location_type_2.content_types.add(ContentType.objects.get_for_model(CircuitTermination))
|
|
24
23
|
status = Status.objects.get_for_model(Circuit).first()
|
|
@@ -26,7 +25,10 @@ class CircuitTerminationModelTestCase(ModelTestCases.BaseModelTestCase):
|
|
|
26
25
|
cid="Circuit 1", provider=provider, circuit_type=circuit_type, status=status
|
|
27
26
|
)
|
|
28
27
|
cls.provider_network = ProviderNetwork.objects.create(name="Provider Network 1", provider=provider)
|
|
29
|
-
|
|
28
|
+
location_status = Status.objects.get_for_model(Location).first()
|
|
29
|
+
cls.location_1 = Location.objects.create(
|
|
30
|
+
name="Department", location_type=location_type_1, status=location_status
|
|
31
|
+
)
|
|
30
32
|
cls.location_2 = Location.objects.filter(location_type=location_type_2)[0]
|
|
31
33
|
|
|
32
34
|
cloud_resource_type = CloudResourceType.objects.get_for_model(CloudNetwork).first()
|
nautobot/circuits/views.py
CHANGED
|
@@ -134,6 +134,7 @@ class CircuitUIViewSet(NautobotUIViewSet):
|
|
|
134
134
|
|
|
135
135
|
class CircuitTerminationPanel(ObjectFieldsPanel):
|
|
136
136
|
def __init__(self, **kwargs):
|
|
137
|
+
self.side = kwargs.pop("side")
|
|
137
138
|
super().__init__(
|
|
138
139
|
fields=(
|
|
139
140
|
"location", # TODO: render location hierarchy
|
|
@@ -161,7 +162,7 @@ class CircuitUIViewSet(NautobotUIViewSet):
|
|
|
161
162
|
return True
|
|
162
163
|
|
|
163
164
|
def get_extra_context(self, context):
|
|
164
|
-
return {"termination": context[self.context_object_key]}
|
|
165
|
+
return {"termination": context[self.context_object_key], "side": self.side}
|
|
165
166
|
|
|
166
167
|
def get_data(self, context):
|
|
167
168
|
"""
|
|
@@ -237,12 +238,14 @@ class CircuitUIViewSet(NautobotUIViewSet):
|
|
|
237
238
|
section=SectionChoices.RIGHT_HALF,
|
|
238
239
|
weight=100,
|
|
239
240
|
context_object_key="circuit_termination_a",
|
|
241
|
+
side=CircuitTerminationSideChoices.SIDE_A,
|
|
240
242
|
),
|
|
241
243
|
CircuitTerminationPanel(
|
|
242
244
|
label="Termination - Z Side",
|
|
243
245
|
section=SectionChoices.RIGHT_HALF,
|
|
244
246
|
weight=200,
|
|
245
247
|
context_object_key="circuit_termination_z",
|
|
248
|
+
side=CircuitTerminationSideChoices.SIDE_Z,
|
|
246
249
|
),
|
|
247
250
|
),
|
|
248
251
|
)
|
nautobot/cloud/api/views.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from nautobot.cloud import filters, models
|
|
2
|
-
from nautobot.extras.api.views import NautobotModelViewSet
|
|
2
|
+
from nautobot.extras.api.views import ModelViewSet, NautobotModelViewSet
|
|
3
3
|
|
|
4
4
|
from . import serializers
|
|
5
5
|
|
|
@@ -26,7 +26,7 @@ class CloudNetworkViewSet(NautobotModelViewSet):
|
|
|
26
26
|
filterset_class = filters.CloudNetworkFilterSet
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class CloudNetworkPrefixAssignmentViewSet(
|
|
29
|
+
class CloudNetworkPrefixAssignmentViewSet(ModelViewSet):
|
|
30
30
|
queryset = models.CloudNetworkPrefixAssignment.objects.all()
|
|
31
31
|
serializer_class = serializers.CloudNetworkPrefixAssignmentSerializer
|
|
32
32
|
filterset_class = filters.CloudNetworkPrefixAssignmentFilterSet
|
|
@@ -38,7 +38,7 @@ class CloudServiceViewSet(NautobotModelViewSet):
|
|
|
38
38
|
filterset_class = filters.CloudServiceFilterSet
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
class CloudServiceNetworkAssignmentViewSet(
|
|
41
|
+
class CloudServiceNetworkAssignmentViewSet(ModelViewSet):
|
|
42
42
|
queryset = models.CloudServiceNetworkAssignment.objects.all()
|
|
43
43
|
serializer_class = serializers.CloudServiceNetworkAssignmentSerializer
|
|
44
44
|
filterset_class = filters.CloudServiceNetworkAssignmentFilterSet
|
nautobot/cloud/filters.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import django_filters
|
|
2
|
-
|
|
3
1
|
from nautobot.cloud import models
|
|
4
2
|
from nautobot.core.filters import (
|
|
5
3
|
BaseFilterSet,
|
|
@@ -11,7 +9,7 @@ from nautobot.dcim.models import Manufacturer
|
|
|
11
9
|
from nautobot.extras.filters import NautobotFilterSet
|
|
12
10
|
from nautobot.extras.models import SecretsGroup
|
|
13
11
|
from nautobot.extras.utils import FeatureQuery
|
|
14
|
-
from nautobot.ipam.
|
|
12
|
+
from nautobot.ipam.filters import PrefixFilter
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
class CloudAccountFilterSet(NautobotFilterSet):
|
|
@@ -98,7 +96,7 @@ class CloudNetworkFilterSet(NautobotFilterSet):
|
|
|
98
96
|
queryset=models.CloudNetwork.objects.all(),
|
|
99
97
|
label="Parent cloud network (name or ID)",
|
|
100
98
|
)
|
|
101
|
-
prefixes =
|
|
99
|
+
prefixes = PrefixFilter()
|
|
102
100
|
|
|
103
101
|
class Meta:
|
|
104
102
|
model = models.CloudNetwork
|
|
@@ -117,8 +115,7 @@ class CloudNetworkPrefixAssignmentFilterSet(BaseFilterSet):
|
|
|
117
115
|
queryset=models.CloudNetwork.objects.all(),
|
|
118
116
|
label="Cloud network (name or ID)",
|
|
119
117
|
)
|
|
120
|
-
|
|
121
|
-
prefix = django_filters.ModelMultipleChoiceFilter(queryset=Prefix.objects.all())
|
|
118
|
+
prefix = PrefixFilter()
|
|
122
119
|
|
|
123
120
|
class Meta:
|
|
124
121
|
model = models.CloudNetworkPrefixAssignment
|
|
@@ -65,6 +65,7 @@ class CloudNetworkTestCase(FilterTestCases.FilterTestCase):
|
|
|
65
65
|
("name",),
|
|
66
66
|
("parent", "parent__id"),
|
|
67
67
|
("parent", "parent__name"),
|
|
68
|
+
("prefixes", "prefixes__id"),
|
|
68
69
|
]
|
|
69
70
|
exclude_q_filter_predicates = [
|
|
70
71
|
"parent__name",
|
|
@@ -79,6 +80,16 @@ class CloudNetworkTestCase(FilterTestCases.FilterTestCase):
|
|
|
79
80
|
queryset = queryset.filter(children__isnull=True)
|
|
80
81
|
return queryset
|
|
81
82
|
|
|
83
|
+
def test_prefixes_filter_by_string(self):
|
|
84
|
+
"""Test filtering by prefix strings as an alternative to pk."""
|
|
85
|
+
prefix = self.queryset.filter(prefixes__isnull=False).first().prefixes.first()
|
|
86
|
+
params = {"prefixes": [prefix.prefix]}
|
|
87
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
88
|
+
self.filterset(params, self.queryset).qs,
|
|
89
|
+
self.queryset.filter(prefixes__network=prefix.network, prefixes__prefix_length=prefix.prefix_length),
|
|
90
|
+
ordered=False,
|
|
91
|
+
)
|
|
92
|
+
|
|
82
93
|
|
|
83
94
|
class CloudNetworkPrefixAssignmentTestCase(FilterTestCases.FilterTestCase):
|
|
84
95
|
queryset = models.CloudNetworkPrefixAssignment.objects.all()
|
|
@@ -89,6 +100,16 @@ class CloudNetworkPrefixAssignmentTestCase(FilterTestCases.FilterTestCase):
|
|
|
89
100
|
("prefix", "prefix__id"),
|
|
90
101
|
]
|
|
91
102
|
|
|
103
|
+
def test_prefix_filter_by_string(self):
|
|
104
|
+
"""Test filtering by prefix strings as an alternative to pk."""
|
|
105
|
+
prefix = self.queryset.first().prefix
|
|
106
|
+
params = {"prefix": [prefix.prefix]}
|
|
107
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
108
|
+
self.filterset(params, self.queryset).qs,
|
|
109
|
+
self.queryset.filter(prefix__network=prefix.network, prefix__prefix_length=prefix.prefix_length),
|
|
110
|
+
ordered=False,
|
|
111
|
+
)
|
|
112
|
+
|
|
92
113
|
|
|
93
114
|
class CloudServiceNetworkAssignmentTestCase(FilterTestCases.FilterTestCase):
|
|
94
115
|
queryset = models.CloudServiceNetworkAssignment.objects.all()
|
nautobot/core/admin.py
CHANGED
|
@@ -9,7 +9,9 @@ from django_celery_beat.models import (
|
|
|
9
9
|
PeriodicTask,
|
|
10
10
|
SolarSchedule,
|
|
11
11
|
)
|
|
12
|
+
import social_django.admin # noqa: F401 # unused-import -- but this import installs the social_django admin
|
|
12
13
|
from social_django.models import Association, Nonce, UserSocialAuth
|
|
14
|
+
import taggit.admin # noqa: F401 # unused-import -- but this import installs the taggit admin
|
|
13
15
|
from taggit.models import Tag
|
|
14
16
|
|
|
15
17
|
from nautobot.core.forms import BootstrapMixin
|
nautobot/core/constants.py
CHANGED
nautobot/core/forms/__init__.py
CHANGED
|
@@ -61,6 +61,7 @@ from nautobot.core.forms.widgets import (
|
|
|
61
61
|
APISelect,
|
|
62
62
|
APISelectMultiple,
|
|
63
63
|
BulkEditNullBooleanSelect,
|
|
64
|
+
ClearableFileInput,
|
|
64
65
|
ColorSelect,
|
|
65
66
|
ContentTypeSelect,
|
|
66
67
|
DatePicker,
|
|
@@ -99,6 +100,7 @@ __all__ = (
|
|
|
99
100
|
"CSVModelForm",
|
|
100
101
|
"CSVMultipleChoiceField",
|
|
101
102
|
"CSVMultipleContentTypeField",
|
|
103
|
+
"ClearableFileInput",
|
|
102
104
|
"ColorSelect",
|
|
103
105
|
"CommentField",
|
|
104
106
|
"ConfirmationForm",
|
nautobot/core/forms/forms.py
CHANGED
|
@@ -10,6 +10,7 @@ from django.forms import formset_factory
|
|
|
10
10
|
from django.urls import reverse
|
|
11
11
|
import yaml
|
|
12
12
|
|
|
13
|
+
from nautobot.core.forms import widgets as nautobot_widgets
|
|
13
14
|
from nautobot.core.utils.filtering import build_lookup_label, get_filter_field_label, get_filterset_parameter_form_field
|
|
14
15
|
from nautobot.ipam import formfields
|
|
15
16
|
|
|
@@ -76,9 +77,9 @@ class BootstrapMixin(forms.BaseForm):
|
|
|
76
77
|
|
|
77
78
|
exempt_widgets = [
|
|
78
79
|
forms.CheckboxInput,
|
|
79
|
-
forms.ClearableFileInput,
|
|
80
80
|
forms.FileInput,
|
|
81
81
|
forms.RadioSelect,
|
|
82
|
+
nautobot_widgets.ClearableFileInput,
|
|
82
83
|
]
|
|
83
84
|
|
|
84
85
|
for field in self.fields.values():
|
nautobot/core/forms/widgets.py
CHANGED
|
@@ -13,6 +13,7 @@ __all__ = (
|
|
|
13
13
|
"APISelect",
|
|
14
14
|
"APISelectMultiple",
|
|
15
15
|
"BulkEditNullBooleanSelect",
|
|
16
|
+
"ClearableFileInput",
|
|
16
17
|
"ColorSelect",
|
|
17
18
|
"ContentTypeSelect",
|
|
18
19
|
"DatePicker",
|
|
@@ -256,3 +257,10 @@ class MultiValueCharInput(StaticSelect2Multiple):
|
|
|
256
257
|
def __init__(self, *args, **kwargs):
|
|
257
258
|
super().__init__(*args, **kwargs)
|
|
258
259
|
self.attrs["class"] = "nautobot-select2-multi-value-char"
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class ClearableFileInput(forms.ClearableFileInput):
|
|
263
|
+
template_name = "widgets/clearable_file.html"
|
|
264
|
+
|
|
265
|
+
class Media:
|
|
266
|
+
js = ["bootstrap-filestyle-1.2.3/bootstrap-filestyle.min.js"]
|
nautobot/core/jobs/__init__.py
CHANGED
|
@@ -229,7 +229,8 @@ class ExportObjectList(Job):
|
|
|
229
229
|
# The force_csv=True attribute is a hack, but much easier than trying to construct a valid HttpRequest
|
|
230
230
|
# object from scratch that passes all implicit and explicit assumptions in Django and DRF.
|
|
231
231
|
serializer = serializer_class(queryset, many=True, context={"request": None}, force_csv=True)
|
|
232
|
-
|
|
232
|
+
# Explicitly add UTF-8 BOM to the data so that Excel will understand non-ASCII characters correctly...
|
|
233
|
+
csv_data = codecs.BOM_UTF8 + renderer.render(serializer.data).encode("utf-8")
|
|
233
234
|
self.create_file(filename + ".csv", csv_data)
|
|
234
235
|
|
|
235
236
|
|