nautobot 2.4.1__py3-none-any.whl → 2.4.3__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.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +1 -1
- nautobot/circuits/tests/integration/test_circuit.py +135 -0
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +43 -0
- nautobot/circuits/tests/integration/test_relationships.py +1 -1
- nautobot/circuits/views.py +4 -1
- nautobot/cloud/api/views.py +3 -3
- nautobot/core/apps/__init__.py +0 -5
- 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/management/commands/generate_performance_test_endpoints.py +268 -0
- nautobot/core/templates/generic/object_bulk_delete.html +1 -1
- nautobot/core/templates/generic/object_bulk_destroy.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 +2 -0
- nautobot/core/templates/widgets/clearable_file.html +5 -0
- nautobot/core/templatetags/helpers.py +3 -3
- nautobot/core/testing/integration.py +469 -12
- nautobot/core/tests/test_commands.py +31 -0
- nautobot/core/tests/test_jobs.py +34 -2
- nautobot/core/tests/test_utils.py +17 -2
- nautobot/core/utils/git.py +7 -2
- nautobot/core/utils/lookup.py +12 -1
- nautobot/core/views/generic.py +10 -2
- nautobot/core/views/mixins.py +22 -7
- nautobot/core/views/utils.py +2 -2
- nautobot/dcim/api/views.py +11 -10
- nautobot/dcim/forms.py +15 -6
- nautobot/dcim/models/devices.py +1 -2
- nautobot/dcim/tables/devices.py +2 -1
- nautobot/dcim/templates/dcim/cable.html +1 -1
- 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/base.html +1 -1
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +3 -3
- nautobot/dcim/templates/dcim/device.html +2 -2
- nautobot/dcim/templates/dcim/device_component.html +1 -1
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/frontport.html +7 -2
- nautobot/dcim/templates/dcim/interface.html +9 -4
- nautobot/dcim/templates/dcim/location.html +1 -1
- nautobot/dcim/templates/dcim/locationtype.html +1 -1
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/manufacturer.html +1 -1
- nautobot/dcim/templates/dcim/platform.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +9 -4
- nautobot/dcim/templates/dcim/poweroutlet.html +14 -4
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +14 -4
- nautobot/dcim/templates/dcim/rack.html +1 -1
- nautobot/dcim/templates/dcim/rackgroup.html +1 -1
- nautobot/dcim/templates/dcim/rackreservation.html +2 -2
- nautobot/dcim/templates/dcim/rearport.html +7 -2
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +30 -0
- nautobot/dcim/tests/integration/test_fileinputpicker.py +87 -0
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +43 -0
- nautobot/dcim/tests/test_models.py +1 -1
- nautobot/dcim/tests/test_views.py +9 -1
- nautobot/dcim/views.py +12 -15
- nautobot/extras/api/serializers.py +33 -0
- nautobot/extras/api/views.py +13 -5
- nautobot/extras/constants.py +1 -0
- nautobot/extras/datasources/git.py +125 -0
- nautobot/extras/forms/forms.py +4 -0
- nautobot/extras/jobs.py +8 -1
- nautobot/extras/migrations/0122_add_graphqlquery_owner_content_type.py +34 -0
- nautobot/extras/models/customfields.py +29 -12
- nautobot/extras/models/datasources.py +85 -0
- nautobot/extras/models/models.py +15 -0
- nautobot/extras/models/relationships.py +17 -5
- nautobot/extras/signals.py +15 -1
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +1 -1
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/customlink.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup.html +1 -1
- nautobot/extras/templates/extras/exporttemplate.html +1 -1
- nautobot/extras/templates/extras/gitrepository.html +1 -1
- nautobot/extras/templates/extras/graphqlquery.html +1 -1
- nautobot/extras/templates/extras/job.html +1 -0
- nautobot/extras/templates/extras/job_detail.html +1 -1
- nautobot/extras/templates/extras/jobbutton_retrieve.html +1 -1
- nautobot/extras/templates/extras/jobhook.html +1 -1
- nautobot/extras/templates/extras/jobresult.html +1 -1
- nautobot/extras/templates/extras/objectchange.html +1 -1
- nautobot/extras/templates/extras/plugin_detail.html +1 -1
- nautobot/extras/templates/extras/relationship.html +1 -63
- nautobot/extras/templates/extras/role_retrieve.html +1 -1
- nautobot/extras/templates/extras/scheduledjob.html +1 -1
- nautobot/extras/templates/extras/secret.html +1 -1
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/status.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templates/extras/webhook.html +1 -1
- nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_interfaces.gql +8 -0
- nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_names.gql +5 -0
- nautobot/extras/tests/git_data/02-invalid-files/graphql_queries/bad_device_names.gql +5 -0
- nautobot/extras/tests/git_helper.py +9 -1
- nautobot/extras/tests/integration/__init__.py +29 -16
- nautobot/extras/tests/test_api.py +6 -0
- nautobot/extras/tests/test_customfields.py +49 -51
- nautobot/extras/tests/test_datasources.py +27 -0
- nautobot/extras/tests/test_dynamicgroups.py +14 -0
- nautobot/extras/tests/test_models.py +283 -0
- nautobot/extras/tests/test_utils.py +22 -1
- nautobot/extras/tests/test_views.py +197 -9
- nautobot/extras/utils.py +47 -8
- nautobot/extras/views.py +84 -26
- nautobot/ipam/api/views.py +3 -3
- nautobot/ipam/forms.py +2 -6
- nautobot/ipam/models.py +8 -2
- nautobot/ipam/tables.py +2 -2
- nautobot/ipam/templates/ipam/ipaddress.html +1 -1
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/templates/ipam/rir.html +1 -1
- nautobot/ipam/templates/ipam/routetarget.html +1 -1
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +1 -1
- nautobot/ipam/templates/ipam/vlangroup.html +1 -1
- nautobot/ipam/templates/ipam/vrf.html +1 -1
- nautobot/ipam/tests/test_models.py +24 -0
- nautobot/ipam/tests/test_utils.py +41 -2
- nautobot/ipam/utils/__init__.py +18 -11
- nautobot/project-static/bootstrap-filestyle-1.2.3/bootstrap-filestyle.min.js +11 -0
- nautobot/project-static/docs/404.html +87 -12
- nautobot/project-static/docs/apps/index.html +88 -13
- nautobot/project-static/docs/apps/nautobot-apps.html +88 -13
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.60a45f97.min.js} +1 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.60a45f97.min.js.map} +1 -1
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js → search.f8cc74c7.min.js} +1 -1
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js.map → search.f8cc74c7.min.js.map} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css → main.a40c8224.min.css} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +87 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +177 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +114 -17
- nautobot/project-static/docs/development/apps/api/configuration-view.html +87 -12
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +87 -12
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +87 -12
- nautobot/project-static/docs/development/apps/api/models/global-search.html +87 -12
- nautobot/project-static/docs/development/apps/api/models/graphql.html +96 -21
- nautobot/project-static/docs/development/apps/api/models/index.html +87 -12
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +89 -14
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +87 -12
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +87 -12
- nautobot/project-static/docs/development/apps/api/prometheus.html +87 -12
- nautobot/project-static/docs/development/apps/api/setup.html +88 -13
- nautobot/project-static/docs/development/apps/api/testing.html +87 -12
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +87 -12
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +87 -12
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +87 -12
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +87 -12
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/base-template.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/index.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/notes.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +87 -12
- nautobot/project-static/docs/development/apps/api/views/urls.html +87 -12
- nautobot/project-static/docs/development/apps/index.html +87 -12
- nautobot/project-static/docs/development/apps/migration/code-updates.html +93 -17
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +89 -14
- nautobot/project-static/docs/development/apps/migration/from-v1.html +90 -15
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +87 -12
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +87 -12
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +87 -12
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +87 -12
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +87 -12
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +87 -12
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +88 -13
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +87 -12
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +87 -12
- nautobot/project-static/docs/development/core/application-registry.html +87 -12
- nautobot/project-static/docs/development/core/best-practices.html +88 -13
- nautobot/project-static/docs/development/core/bootstrap-ui.html +88 -13
- nautobot/project-static/docs/development/core/caching.html +87 -12
- nautobot/project-static/docs/development/core/controllers.html +87 -12
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +94 -19
- nautobot/project-static/docs/development/core/generic-views.html +87 -12
- nautobot/project-static/docs/development/core/getting-started.html +89 -14
- nautobot/project-static/docs/development/core/homepage.html +87 -12
- nautobot/project-static/docs/development/core/index.html +88 -13
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +90 -15
- nautobot/project-static/docs/development/core/model-checklist.html +88 -13
- nautobot/project-static/docs/development/core/model-features.html +87 -12
- nautobot/project-static/docs/development/core/natural-keys.html +87 -12
- nautobot/project-static/docs/development/core/navigation-menu.html +88 -13
- nautobot/project-static/docs/development/core/release-checklist.html +88 -13
- nautobot/project-static/docs/development/core/role-internals.html +87 -12
- nautobot/project-static/docs/development/core/settings.html +88 -13
- nautobot/project-static/docs/development/core/style-guide.html +91 -16
- nautobot/project-static/docs/development/core/templates.html +88 -13
- nautobot/project-static/docs/development/core/testing.html +87 -12
- nautobot/project-static/docs/development/core/ui-component-framework.html +87 -12
- nautobot/project-static/docs/development/core/user-preferences.html +87 -12
- nautobot/project-static/docs/development/index.html +87 -12
- nautobot/project-static/docs/development/jobs/index.html +95 -13
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +90 -14
- nautobot/project-static/docs/index.html +90 -14
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +89 -14
- nautobot/project-static/docs/overview/design_philosophy.html +87 -12
- nautobot/project-static/docs/release-notes/index.html +87 -12
- nautobot/project-static/docs/release-notes/version-1.0.html +89 -14
- nautobot/project-static/docs/release-notes/version-1.1.html +89 -14
- nautobot/project-static/docs/release-notes/version-1.2.html +90 -15
- nautobot/project-static/docs/release-notes/version-1.3.html +88 -13
- nautobot/project-static/docs/release-notes/version-1.4.html +104 -29
- nautobot/project-static/docs/release-notes/version-1.5.html +95 -20
- nautobot/project-static/docs/release-notes/version-1.6.html +91 -16
- nautobot/project-static/docs/release-notes/version-2.0.html +97 -22
- nautobot/project-static/docs/release-notes/version-2.1.html +94 -19
- nautobot/project-static/docs/release-notes/version-2.2.html +88 -13
- nautobot/project-static/docs/release-notes/version-2.3.html +91 -16
- nautobot/project-static/docs/release-notes/version-2.4.html +465 -12
- nautobot/project-static/docs/requirements.txt +1 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +296 -288
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +90 -15
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +87 -12
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +91 -16
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +87 -12
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +88 -13
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +90 -15
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +87 -12
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +95 -20
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +90 -15
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +88 -13
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +87 -12
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +91 -16
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +87 -12
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +102 -27
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +89 -14
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +87 -12
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +88 -13
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +87 -12
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +87 -12
- nautobot/project-static/docs/user-guide/administration/installation/index.html +87 -12
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +88 -13
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +93 -18
- nautobot/project-static/docs/user-guide/administration/installation/services.html +88 -13
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +87 -12
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +87 -12
- nautobot/project-static/docs/user-guide/administration/security/index.html +9420 -0
- nautobot/project-static/docs/user-guide/administration/security/notices.html +9844 -0
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +87 -12
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +88 -13
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +87 -12
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +98 -20
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +87 -12
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +99 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +90 -15
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +188 -30
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +87 -12
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +87 -12
- nautobot/project-static/docs/user-guide/index.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +88 -13
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +407 -14
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +90 -15
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +89 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +93 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +87 -12
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +87 -12
- nautobot/project-static/js/dropdown.js +28 -0
- nautobot/tenancy/forms.py +9 -0
- nautobot/tenancy/templates/tenancy/tenant.html +1 -2
- 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_views.py +5 -1
- nautobot/tenancy/urls.py +7 -79
- nautobot/tenancy/views.py +51 -80
- nautobot/virtualization/templates/virtualization/cluster.html +1 -1
- nautobot/virtualization/templates/virtualization/clustergroup.html +1 -1
- nautobot/virtualization/templates/virtualization/clustertype.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/vminterface.html +1 -1
- nautobot/wireless/api/serializers.py +6 -1
- nautobot/wireless/api/views.py +3 -3
- nautobot/wireless/tests/test_api.py +5 -0
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/METADATA +12 -12
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/RECORD +459 -443
- nautobot/dcim/tests/integration/test_device_bulk_delete.py +0 -189
- nautobot/dcim/tests/integration/test_device_bulk_edit.py +0 -181
- /nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css.map → main.a40c8224.min.css.map} +0 -0
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/NOTICE +0 -0
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/WHEEL +0 -0
- {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/entry_points.txt +0 -0
|
@@ -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)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
from nautobot.circuits.models import Circuit, CircuitType, Provider
|
|
4
|
+
from nautobot.core.testing.integration import (
|
|
5
|
+
BulkOperationsTestCases,
|
|
6
|
+
)
|
|
7
|
+
from nautobot.extras.models import Status
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CircuitBulkOperationsTestCase(BulkOperationsTestCases.BulkOperationsTestCase):
|
|
11
|
+
"""
|
|
12
|
+
Test circuits bulk edit / delete operations.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
model_menu_path = ("Circuits", "Circuits")
|
|
16
|
+
model_base_viewname = "circuits:circuit"
|
|
17
|
+
model_edit_data = {"commit_rate": "12345"}
|
|
18
|
+
model_filter_by = {"circuit_type": "Copper"}
|
|
19
|
+
model_class = Circuit
|
|
20
|
+
|
|
21
|
+
def setup_items(self):
|
|
22
|
+
Circuit.objects.all().delete()
|
|
23
|
+
|
|
24
|
+
# Create locations for test
|
|
25
|
+
self.create_circuit()
|
|
26
|
+
self.create_circuit()
|
|
27
|
+
self.create_circuit()
|
|
28
|
+
self.create_circuit("Copper")
|
|
29
|
+
self.create_circuit("Copper")
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def create_circuit(circuit_type="Fiber"):
|
|
33
|
+
circuit_id = f"TestCircuit-{str(uuid.uuid4())[:6]}"
|
|
34
|
+
provider, _ = Provider.objects.get_or_create(name="A Test Provider")
|
|
35
|
+
circuit_type, _ = CircuitType.objects.get_or_create(name=circuit_type)
|
|
36
|
+
|
|
37
|
+
circuit_status = Status.objects.get_for_model(Circuit).first()
|
|
38
|
+
Circuit.objects.get_or_create(
|
|
39
|
+
cid=circuit_id,
|
|
40
|
+
provider=provider,
|
|
41
|
+
status=circuit_status,
|
|
42
|
+
circuit_type=circuit_type,
|
|
43
|
+
)
|
|
@@ -19,7 +19,7 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
|
|
|
19
19
|
self.user.is_superuser = True
|
|
20
20
|
self.user.save()
|
|
21
21
|
self.login(self.user.username, self.password)
|
|
22
|
-
location_type = LocationType.objects.
|
|
22
|
+
location_type, _ = LocationType.objects.get_or_create(name="Campus")
|
|
23
23
|
location_ct = ContentType.objects.get_for_model(Location)
|
|
24
24
|
circuit_termination_ct = ContentType.objects.get_for_model(CircuitTermination)
|
|
25
25
|
provider_ct = ContentType.objects.get_for_model(Provider)
|
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/core/apps/__init__.py
CHANGED
|
@@ -367,11 +367,6 @@ class CoreConfig(NautobotConfig):
|
|
|
367
367
|
|
|
368
368
|
super().ready()
|
|
369
369
|
|
|
370
|
-
# Register jobs last after everything else has been done.
|
|
371
|
-
from nautobot.core.celery import import_jobs
|
|
372
|
-
|
|
373
|
-
import_jobs()
|
|
374
|
-
|
|
375
370
|
|
|
376
371
|
class NautobotConstanceConfig(ConstanceConfig):
|
|
377
372
|
"""Override "Constance" app name to "Configuration"."""
|
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"]
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from django.core.management.base import BaseCommand
|
|
5
|
+
from django.urls import get_resolver
|
|
6
|
+
from django.utils.http import urlencode
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from nautobot.core.utils.lookup import get_model_for_view_name
|
|
10
|
+
|
|
11
|
+
# List of view names that are excluded for various error responses
|
|
12
|
+
EXCLUDED_VIEW_NAMES = [
|
|
13
|
+
"graphql-api", # "Method \\"GET\\" not allowed."
|
|
14
|
+
"graphql", # "Must provide query string."
|
|
15
|
+
"dcim-api:device-napalm", # "No platform is configured for this device."
|
|
16
|
+
"dcim-api:connected-device-list", # "Request must include \\"peer_device\\" and \\"peer_interface\\" filters."
|
|
17
|
+
"login",
|
|
18
|
+
"logout",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# List of reversed url name suffixes that are used to identify GET endpoints UI and API
|
|
22
|
+
GET_ENDPOINT_SUFFIXES = ("_list", "_notes", "_changelog", "-detail", "-list", "-notes")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Command(BaseCommand):
|
|
26
|
+
"""
|
|
27
|
+
Example usage: `nautobot-server generate_performance_test_endpoints > endpoints.yml`
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
help = "List all relevant performance test url patterns in Nautobot Core"
|
|
31
|
+
|
|
32
|
+
def add_arguments(self, parser):
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--output-file",
|
|
35
|
+
help="A file path string that specifies the output file to write the endpoints to.",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def handle(self, *args, **options):
|
|
39
|
+
# Get the URL resolver
|
|
40
|
+
url_patterns = get_resolver().url_patterns
|
|
41
|
+
|
|
42
|
+
# Group the urls by app names
|
|
43
|
+
self.app_name_to_urls = {}
|
|
44
|
+
self.app_name_to_urls["endpoints"] = {}
|
|
45
|
+
# Fetch and store the urls by app names in the dictionary
|
|
46
|
+
self.fetch_urls(url_patterns)
|
|
47
|
+
for view_name, url_patterns in self.app_name_to_urls["endpoints"].items():
|
|
48
|
+
# De-duplicate the URL patterns and sort them.
|
|
49
|
+
self.app_name_to_urls["endpoints"][view_name] = sorted(list(set(url_patterns)))
|
|
50
|
+
|
|
51
|
+
if filepath := options.get("output_file"):
|
|
52
|
+
# Output the endpoints to a yaml file
|
|
53
|
+
with open(filepath, "w") as outfile:
|
|
54
|
+
yaml.dump(self.app_name_to_urls, outfile, sort_keys=True)
|
|
55
|
+
else:
|
|
56
|
+
# Output the endpoints to the console
|
|
57
|
+
self.stdout.write(yaml.dump(self.app_name_to_urls, sort_keys=True))
|
|
58
|
+
|
|
59
|
+
def is_eligible_get_endpoint(self, view_name):
|
|
60
|
+
"""
|
|
61
|
+
Check if the view is a GET endpoint and if it is eligible for performance testing.
|
|
62
|
+
"""
|
|
63
|
+
if view_name not in EXCLUDED_VIEW_NAMES and (view_name.endswith(GET_ENDPOINT_SUFFIXES) or "_" not in view_name):
|
|
64
|
+
return True
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def append_urls_to_dict(self, url_pattern, model_class, view_name, is_api_endpoint=False):
|
|
68
|
+
"""
|
|
69
|
+
URL patterns are stored in the dictionary in the following format:
|
|
70
|
+
- Any model detail view URL pattern that contains `<uuid:pk>` or `(?P<pk>[/.]+)` will have two endpoints:
|
|
71
|
+
- One with the `model_class.objects.first().pk`
|
|
72
|
+
- One with the `model_class.objects.last().pk`
|
|
73
|
+
- Any model list view URL pattern will have two endpoints:
|
|
74
|
+
- One with default pagination
|
|
75
|
+
- One with custom pagination (5 pages with <total_object_count//5> instances per page)
|
|
76
|
+
- Any generic endpoint like `core:home` will have one endpoint which is the URL pattern itself.
|
|
77
|
+
"""
|
|
78
|
+
if not model_class:
|
|
79
|
+
# A generic endpoint like `core:home`
|
|
80
|
+
if view_name not in self.app_name_to_urls["endpoints"]:
|
|
81
|
+
self.app_name_to_urls["endpoints"][view_name] = []
|
|
82
|
+
self.app_name_to_urls["endpoints"][view_name].append(url_pattern)
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# Handle detail view url patterns
|
|
86
|
+
total_count = len(model_class.objects.all())
|
|
87
|
+
if "_list" not in view_name and "-list" not in view_name:
|
|
88
|
+
# If the model class is found, then we know we are dealing with a model related endpoint
|
|
89
|
+
if total_count == 0:
|
|
90
|
+
# TODO handle the case where there is no instances of the model is found
|
|
91
|
+
self.stderr.write(f"Not enough instances of {model_class} found, need at least 1")
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
# Identify the placeholder for the uuid
|
|
95
|
+
replace_string = ""
|
|
96
|
+
if "<uuid:pk>" in url_pattern:
|
|
97
|
+
replace_string = "<uuid:pk>"
|
|
98
|
+
elif "(?P<pk>[/.]+)" in url_pattern:
|
|
99
|
+
replace_string = "(?P<pk>[/.]+)"
|
|
100
|
+
|
|
101
|
+
if replace_string:
|
|
102
|
+
# Replace the uuid with the actual uuid
|
|
103
|
+
if total_count == 1:
|
|
104
|
+
# Case where there is only one instance of the model
|
|
105
|
+
first_url_pattern = url_pattern.replace(replace_string, str(model_class.objects.first().pk))
|
|
106
|
+
if view_name not in self.app_name_to_urls["endpoints"]:
|
|
107
|
+
self.app_name_to_urls["endpoints"][view_name] = []
|
|
108
|
+
self.app_name_to_urls["endpoints"][view_name].append(first_url_pattern)
|
|
109
|
+
else:
|
|
110
|
+
# Case where there is more than one instance of the model
|
|
111
|
+
first_url_pattern = url_pattern.replace(replace_string, str(model_class.objects.first().pk))
|
|
112
|
+
second_url_pattern = url_pattern.replace(replace_string, str(model_class.objects.last().pk))
|
|
113
|
+
if view_name not in self.app_name_to_urls["endpoints"]:
|
|
114
|
+
self.app_name_to_urls["endpoints"][view_name] = []
|
|
115
|
+
self.app_name_to_urls["endpoints"][view_name].append(first_url_pattern)
|
|
116
|
+
self.app_name_to_urls["endpoints"][view_name].append(second_url_pattern)
|
|
117
|
+
# Handle list view url patterns
|
|
118
|
+
else:
|
|
119
|
+
if view_name not in self.app_name_to_urls["endpoints"]:
|
|
120
|
+
self.app_name_to_urls["endpoints"][view_name] = []
|
|
121
|
+
# One endpoint with default pagination
|
|
122
|
+
self.app_name_to_urls["endpoints"][view_name].append(url_pattern)
|
|
123
|
+
page_query_parameter = 5
|
|
124
|
+
per_page_query_parameter = total_count // page_query_parameter
|
|
125
|
+
if not is_api_endpoint:
|
|
126
|
+
query_params = urlencode(
|
|
127
|
+
{
|
|
128
|
+
"per_page": per_page_query_parameter,
|
|
129
|
+
"page": page_query_parameter,
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
query_params = urlencode(
|
|
134
|
+
{
|
|
135
|
+
"limit": per_page_query_parameter,
|
|
136
|
+
"offset": per_page_query_parameter * (page_query_parameter - 1),
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
# One endpoint with non-default pagination
|
|
140
|
+
self.app_name_to_urls["endpoints"][view_name].append(url_pattern + f"?{query_params}")
|
|
141
|
+
|
|
142
|
+
def construct_view_name_and_url_pattern(self, pattern) -> tuple[Optional[str], Optional[str], bool]:
|
|
143
|
+
"""
|
|
144
|
+
Args:
|
|
145
|
+
pattern (django.urls.resolvers.URLPattern): A URL pattern object.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
url_pattern (str): The URL pattern of the view.
|
|
149
|
+
view_name (str): The URL name of the view.
|
|
150
|
+
is_api_endpoint (bool): True if the endpoint is an API endpoint, False otherwise.
|
|
151
|
+
"""
|
|
152
|
+
lookup_str_list = pattern.lookup_str.split(".")
|
|
153
|
+
|
|
154
|
+
# Determine if the endpoint belongs to a plugin
|
|
155
|
+
is_app = lookup_str_list[0] != "nautobot"
|
|
156
|
+
is_api_endpoint = "api" in lookup_str_list
|
|
157
|
+
# One of the nautobot apps: nautobot.circuits, nautobot.dcim, and etc. if not is_app
|
|
158
|
+
# One of the plugins: example_app, and etc. if is_app
|
|
159
|
+
app_name = lookup_str_list[0] if is_app else lookup_str_list[1]
|
|
160
|
+
|
|
161
|
+
model = pattern.default_args.get("model", None)
|
|
162
|
+
if model:
|
|
163
|
+
app_name = model._meta.app_label
|
|
164
|
+
|
|
165
|
+
if app_name == "users" and pattern.name in ["login", "logout"]:
|
|
166
|
+
# No need to test the login and logout endpoints for performance testing
|
|
167
|
+
url_pattern = f"/{pattern.pattern}" # /login, /logout
|
|
168
|
+
view_name = f"{pattern.name}" # login, logout
|
|
169
|
+
elif app_name == "core":
|
|
170
|
+
# Handle the special case where a view exist in the core app
|
|
171
|
+
# but its url pattern and view name does not include the prefix "/core" or "core:"
|
|
172
|
+
# ['nautobot', 'core', "views", "HomeView"]
|
|
173
|
+
# ['nautobot', 'core', "api", "views", "APIRootView"]
|
|
174
|
+
if pattern.name in ["api-root", "api-status", "graphql-api"]:
|
|
175
|
+
is_api_endpoint = True
|
|
176
|
+
url_pattern = f"/api/{pattern.pattern}" # /api/status
|
|
177
|
+
view_name = f"{pattern.name}" # api-status
|
|
178
|
+
elif pattern.name in ["home", "about", "search", "worker-status", "graphql", "metrics"]:
|
|
179
|
+
url_pattern = f"/{pattern.pattern}" # /home, /about, /search
|
|
180
|
+
view_name = f"{pattern.name}" # home, about, search
|
|
181
|
+
else:
|
|
182
|
+
url_pattern = None
|
|
183
|
+
view_name = None
|
|
184
|
+
elif app_name == "extras" and "plugins" in lookup_str_list:
|
|
185
|
+
# Handle the special case first for Installed apps related view is nested under the extras app.
|
|
186
|
+
# ['nautobot', 'extras', 'plugins', 'views', 'InstalledAppsView']
|
|
187
|
+
|
|
188
|
+
# We need special case handling to determine if the endpoint is an api endpoint as well for this view
|
|
189
|
+
view_class_name = lookup_str_list[-1]
|
|
190
|
+
if "API" in view_class_name:
|
|
191
|
+
is_api_endpoint = True
|
|
192
|
+
apps_or_plugins = "plugins" if "plugins" in pattern.name else "apps"
|
|
193
|
+
if is_api_endpoint:
|
|
194
|
+
url_pattern = f"/api/{apps_or_plugins}/{pattern.pattern}" # /api/apps/installed-apps
|
|
195
|
+
view_name = f"{apps_or_plugins}-api:{pattern.name}" # apps-api:apps-list
|
|
196
|
+
else:
|
|
197
|
+
url_pattern = f"/{apps_or_plugins}/{pattern.pattern}" # /apps/installed-apps
|
|
198
|
+
view_name = f"{apps_or_plugins}:{pattern.name}" # apps:apps_list
|
|
199
|
+
elif is_api_endpoint:
|
|
200
|
+
if not is_app:
|
|
201
|
+
# One of the nautobot apps: nautobot.circuits, nautobot.dcim, and etc.
|
|
202
|
+
url_pattern = f"/api/{app_name}/{pattern.pattern}" # /api/dcim/devices/
|
|
203
|
+
app_name = f"{app_name}-api" # dcim-api
|
|
204
|
+
view_name = f"{app_name}:{pattern.name}" # dcim-api:device-list
|
|
205
|
+
else:
|
|
206
|
+
api_app_name = f"{app_name}-api" # example_app-api
|
|
207
|
+
view_name = (
|
|
208
|
+
f"plugins-api:{api_app_name}:{pattern.name}" # plugins-api:example_app-api:examplemodel-list
|
|
209
|
+
)
|
|
210
|
+
app_name = app_name.replace("_", "-") # example_app -> example-app
|
|
211
|
+
url_pattern = f"/api/plugins/{app_name}/{pattern.pattern}" # /api/plugins/example-app/models/
|
|
212
|
+
else:
|
|
213
|
+
if not is_app:
|
|
214
|
+
url_pattern = f"/{app_name}/{pattern.pattern}" # /dcim/devices/
|
|
215
|
+
view_name = f"{app_name}:{pattern.name}" # dcim:device_list
|
|
216
|
+
else:
|
|
217
|
+
view_name = f"plugins:{app_name}:{pattern.name}" # plugins:example_app:examplemodel_list
|
|
218
|
+
app_name = app_name.replace("_", "-") # example_app -> example-app
|
|
219
|
+
url_pattern = f"/plugins/{app_name}/{pattern.pattern}" # /plugins/example-app/models/
|
|
220
|
+
|
|
221
|
+
return url_pattern, view_name, is_api_endpoint
|
|
222
|
+
|
|
223
|
+
def fetch_urls(self, url_patterns):
|
|
224
|
+
"""
|
|
225
|
+
Store the URL patterns in the dictionary to output an .YAML file
|
|
226
|
+
The dictionary will have the following structure:
|
|
227
|
+
{
|
|
228
|
+
"endpoints": {
|
|
229
|
+
<app_name>:<view_name>: [
|
|
230
|
+
<url_pattern_1>,
|
|
231
|
+
<url_pattern_2>,
|
|
232
|
+
],
|
|
233
|
+
dcim:device: [
|
|
234
|
+
"/dcim/devices/cfbd447f-d563-4fac-bb75-bdda70ab4e80/",
|
|
235
|
+
"/dcim/devices/38471bfe-0aca-4e09-b545-b0f90280fb66/",
|
|
236
|
+
],
|
|
237
|
+
dcim-api:device-detail: [
|
|
238
|
+
"/api/dcim/devices/cfbd447f-d563-4fac-bb75-bdda70ab4e80/",
|
|
239
|
+
"/api/dcim/devices/38471bfe-0aca-4e09-b545-b0f90280fb66/",
|
|
240
|
+
],
|
|
241
|
+
...
|
|
242
|
+
},
|
|
243
|
+
...
|
|
244
|
+
"""
|
|
245
|
+
for pattern in url_patterns:
|
|
246
|
+
if hasattr(pattern, "url_patterns"):
|
|
247
|
+
# If it's a nested URL pattern, recursively list its URLs
|
|
248
|
+
self.fetch_urls(pattern.url_patterns)
|
|
249
|
+
else:
|
|
250
|
+
# Only fetch urls from relevant apps
|
|
251
|
+
if pattern.lookup_str.startswith(("nautobot.", *settings.PLUGINS)):
|
|
252
|
+
url_pattern, view_name, is_api_endpoint = self.construct_view_name_and_url_pattern(pattern)
|
|
253
|
+
# We do not need to test the ?format=<json,csv,api> endpoints and non-GET endpoints
|
|
254
|
+
if (
|
|
255
|
+
url_pattern is not None
|
|
256
|
+
and "(?P<format>[a-z0-9]+)" not in url_pattern
|
|
257
|
+
and "<drf_format_suffix:format>" not in url_pattern
|
|
258
|
+
and self.is_eligible_get_endpoint(view_name)
|
|
259
|
+
):
|
|
260
|
+
# Replace "^" and "$" from the url pattern
|
|
261
|
+
url_pattern = url_pattern.replace("^", "").replace("$", "")
|
|
262
|
+
# Retrieve the model class for the view name
|
|
263
|
+
try:
|
|
264
|
+
model_class = get_model_for_view_name(view_name)
|
|
265
|
+
except ValueError:
|
|
266
|
+
# In case it is a generic view like /home, /about, /search
|
|
267
|
+
model_class = None
|
|
268
|
+
self.append_urls_to_dict(url_pattern, model_class, view_name, is_api_endpoint)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_bulk_destroy.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
{% block content %}
|
|
8
8
|
<div class="row">
|
|
9
9
|
<div class="col-md-8 col-md-offset-2">
|
|
10
|
-
<div class="panel panel-danger">
|
|
10
|
+
<div class="panel panel-danger" id="confirm-bulk-deletion">
|
|
11
11
|
<div class="panel-heading"><strong>Confirm Bulk Deletion</strong></div>
|
|
12
12
|
<div class="panel-body">
|
|
13
13
|
<p><strong>Warning:</strong> The following operation will delete {{ total_objs_to_delete }} {{ obj_type_plural }}. {% if not delete_all %}Please carefully review the {{ obj_type_plural }} to be deleted and confirm below.{% endif %}</p>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_bulk_update.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_bulk_create.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_destroy.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_create.html' %}
|
|
2
|
-
{% comment %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|