nautobot 2.4.5__py3-none-any.whl → 2.4.7__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/apps/forms.py +2 -0
- nautobot/circuits/templates/circuits/providernetwork.html +1 -1
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +2 -55
- nautobot/circuits/views.py +20 -23
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +2 -40
- nautobot/cloud/views.py +12 -0
- nautobot/core/api/mixins.py +10 -0
- nautobot/core/api/urls.py +2 -2
- nautobot/core/api/views.py +39 -1
- nautobot/core/celery/encoders.py +2 -2
- nautobot/core/forms/__init__.py +2 -0
- nautobot/core/forms/fields.py +23 -7
- nautobot/core/forms/utils.py +1 -0
- nautobot/core/forms/widgets.py +18 -0
- nautobot/core/jobs/bulk_actions.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +1 -1
- nautobot/core/models/name_color_content_types.py +9 -0
- nautobot/core/models/validators.py +7 -0
- nautobot/core/settings.py +0 -14
- nautobot/core/settings.yaml +0 -28
- nautobot/core/tables.py +6 -1
- nautobot/core/templates/generic/object_retrieve.html +1 -1
- nautobot/core/templates/widgets/sluginput.html +5 -1
- nautobot/core/templatetags/helpers.py +15 -1
- nautobot/core/testing/api.py +18 -0
- nautobot/core/testing/integration.py +6 -2
- nautobot/core/tests/nautobot_config.py +0 -2
- nautobot/core/tests/runner.py +17 -140
- nautobot/core/tests/test_api.py +4 -4
- nautobot/core/tests/test_authentication.py +83 -4
- nautobot/core/tests/test_forms.py +11 -8
- nautobot/core/tests/test_graphql.py +9 -0
- nautobot/core/tests/test_jobs.py +7 -0
- nautobot/core/ui/object_detail.py +47 -3
- nautobot/core/utils/lookup.py +2 -2
- nautobot/dcim/factory.py +2 -0
- nautobot/dcim/filters/__init__.py +5 -0
- nautobot/dcim/forms.py +27 -1
- nautobot/dcim/migrations/0068_alter_softwareimagefile_download_url.py +19 -0
- nautobot/dcim/migrations/0069_softwareimagefile_external_integration.py +25 -0
- nautobot/dcim/models/devices.py +9 -2
- nautobot/dcim/models/locations.py +9 -0
- nautobot/dcim/tables/devices.py +1 -0
- nautobot/dcim/templates/dcim/device_list.html +1 -1
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/manufacturer.html +1 -63
- nautobot/dcim/templates/dcim/module_list.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +4 -0
- nautobot/dcim/tests/integration/test_module_bay_position.py +125 -0
- nautobot/dcim/tests/test_api.py +74 -31
- nautobot/dcim/tests/test_filters.py +2 -0
- nautobot/dcim/tests/test_models.py +78 -0
- nautobot/dcim/tests/test_views.py +7 -1
- nautobot/dcim/urls.py +1 -45
- nautobot/dcim/views.py +35 -66
- nautobot/extras/choices.py +4 -0
- nautobot/extras/filters/__init__.py +6 -0
- nautobot/extras/forms/forms.py +83 -11
- nautobot/extras/models/customfields.py +10 -9
- nautobot/extras/plugins/marketplace_manifest.yml +18 -0
- nautobot/extras/signals.py +43 -4
- nautobot/extras/tables.py +4 -5
- nautobot/extras/tasks.py +4 -2
- nautobot/extras/templates/extras/contact_retrieve.html +1 -58
- nautobot/extras/templates/extras/exporttemplate.html +1 -53
- nautobot/extras/templates/extras/inc/panel_changelog.html +1 -1
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/status.html +1 -37
- nautobot/extras/templates/extras/team_retrieve.html +1 -58
- nautobot/extras/tests/integration/test_notes.py +1 -1
- nautobot/extras/tests/test_api.py +22 -7
- nautobot/extras/tests/test_changelog.py +4 -4
- nautobot/extras/tests/test_customfields.py +27 -0
- nautobot/extras/tests/test_plugins.py +19 -13
- nautobot/extras/tests/test_relationships.py +9 -0
- nautobot/extras/tests/test_tags.py +2 -2
- nautobot/extras/tests/test_views.py +37 -6
- nautobot/extras/urls.py +3 -100
- nautobot/extras/views.py +111 -133
- nautobot/ipam/tables.py +7 -2
- nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -41
- nautobot/ipam/templates/ipam/service.html +2 -46
- nautobot/ipam/templates/ipam/service_edit.html +1 -17
- nautobot/ipam/templates/ipam/service_retrieve.html +7 -0
- nautobot/ipam/tests/migration/__init__.py +0 -0
- nautobot/ipam/tests/migration/test_migrations.py +510 -0
- nautobot/ipam/tests/test_api.py +66 -36
- nautobot/ipam/tests/test_filters.py +0 -10
- nautobot/ipam/tests/test_views.py +44 -2
- nautobot/ipam/urls.py +2 -47
- nautobot/ipam/utils/migrations.py +185 -152
- nautobot/ipam/utils/testing.py +177 -0
- nautobot/ipam/views.py +95 -157
- nautobot/project-static/css/base.css +5 -0
- nautobot/project-static/docs/404.html +0 -2
- nautobot/project-static/docs/apps/index.html +0 -2
- nautobot/project-static/docs/apps/nautobot-apps.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +62 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +47 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +70 -5
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +0 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +0 -2
- nautobot/project-static/docs/development/apps/api/configuration-view.html +0 -2
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +0 -2
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +0 -2
- nautobot/project-static/docs/development/apps/api/models/global-search.html +0 -2
- nautobot/project-static/docs/development/apps/api/models/graphql.html +0 -2
- nautobot/project-static/docs/development/apps/api/models/index.html +0 -2
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +0 -2
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +0 -2
- nautobot/project-static/docs/development/apps/api/prometheus.html +0 -2
- nautobot/project-static/docs/development/apps/api/setup.html +0 -2
- nautobot/project-static/docs/development/apps/api/testing.html +0 -89
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +0 -2
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +0 -2
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +0 -2
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +0 -2
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/base-template.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/index.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/notes.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +0 -2
- nautobot/project-static/docs/development/apps/api/views/urls.html +0 -2
- nautobot/project-static/docs/development/apps/index.html +0 -2
- nautobot/project-static/docs/development/apps/migration/code-updates.html +0 -2
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +1 -3
- nautobot/project-static/docs/development/apps/migration/from-v1.html +0 -2
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +0 -2
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +0 -2
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +0 -2
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +0 -2
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +0 -2
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +0 -2
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +0 -2
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +0 -2
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +0 -2
- nautobot/project-static/docs/development/core/application-registry.html +0 -2
- nautobot/project-static/docs/development/core/best-practices.html +3 -5
- nautobot/project-static/docs/development/core/bootstrap-ui.html +0 -2
- nautobot/project-static/docs/development/core/caching.html +0 -2
- nautobot/project-static/docs/development/core/controllers.html +0 -2
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +0 -2
- nautobot/project-static/docs/development/core/generic-views.html +0 -2
- nautobot/project-static/docs/development/core/getting-started.html +78 -109
- nautobot/project-static/docs/development/core/homepage.html +0 -2
- nautobot/project-static/docs/development/core/index.html +0 -2
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +0 -2
- nautobot/project-static/docs/development/core/model-checklist.html +0 -2
- nautobot/project-static/docs/development/core/model-features.html +0 -2
- nautobot/project-static/docs/development/core/natural-keys.html +0 -2
- nautobot/project-static/docs/development/core/navigation-menu.html +0 -2
- nautobot/project-static/docs/development/core/release-checklist.html +1 -3
- nautobot/project-static/docs/development/core/role-internals.html +0 -2
- nautobot/project-static/docs/development/core/settings.html +0 -2
- nautobot/project-static/docs/development/core/style-guide.html +1 -3
- nautobot/project-static/docs/development/core/templates.html +0 -2
- nautobot/project-static/docs/development/core/testing.html +24 -200
- nautobot/project-static/docs/development/core/ui-component-framework.html +0 -2
- nautobot/project-static/docs/development/core/user-preferences.html +0 -2
- nautobot/project-static/docs/development/index.html +0 -2
- nautobot/project-static/docs/development/jobs/index.html +0 -2
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +0 -2
- nautobot/project-static/docs/index.html +0 -2
- nautobot/project-static/docs/media/user-guide/administration/getting-started/nautobot-cloud.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +1 -3
- nautobot/project-static/docs/overview/design_philosophy.html +0 -2
- nautobot/project-static/docs/release-notes/index.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.0.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.1.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.2.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.3.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.4.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.5.html +0 -2
- nautobot/project-static/docs/release-notes/version-1.6.html +0 -2
- nautobot/project-static/docs/release-notes/version-2.0.html +0 -2
- nautobot/project-static/docs/release-notes/version-2.1.html +0 -2
- nautobot/project-static/docs/release-notes/version-2.2.html +0 -2
- nautobot/project-static/docs/release-notes/version-2.3.html +0 -2
- nautobot/project-static/docs/release-notes/version-2.4.html +364 -3
- 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 +0 -2
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +0 -2
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +0 -2
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +0 -2
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +0 -2
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +2 -50
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +71 -2
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +0 -2
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +0 -2
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +0 -2
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +0 -2
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/index.html +257 -18
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +0 -2
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +0 -2
- nautobot/project-static/docs/user-guide/administration/installation/services.html +0 -2
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +0 -2
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +0 -2
- nautobot/project-static/docs/user-guide/administration/security/index.html +0 -2
- nautobot/project-static/docs/user-guide/administration/security/notices.html +0 -2
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +1 -3
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +0 -2
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +2 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +0 -2
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -13
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +8 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +1 -2
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +40 -27
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -6
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +1 -3
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +77 -7
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +1 -3
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +0 -3
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -3
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +0 -2
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +0 -2
- nautobot/project-static/docs/user-guide/index.html +89 -4
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +0 -2
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +207 -124
- nautobot/project-static/js/forms.js +88 -37
- nautobot/project-static/js/homepage_layout.js +12 -3
- nautobot/virtualization/forms.py +20 -0
- nautobot/virtualization/templates/virtualization/clustergroup.html +1 -39
- nautobot/virtualization/templates/virtualization/clustertype.html +1 -0
- nautobot/virtualization/tests/test_api.py +14 -3
- nautobot/virtualization/tests/test_views.py +10 -2
- nautobot/virtualization/urls.py +10 -93
- nautobot/virtualization/views.py +33 -72
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/METADATA +6 -5
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/RECORD +407 -402
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/WHEEL +1 -1
- nautobot/core/tests/performance_baselines.yml +0 -8900
- nautobot/dcim/templates/dcim/modulebay_create.html +0 -39
- nautobot/ipam/tests/test_migrations.py +0 -462
- /nautobot/ipam/templates/ipam/{namespace_ipaddresses.html → namespace_ip_addresses.html} +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/NOTICE +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/entry_points.txt +0 -0
nautobot/apps/forms.py
CHANGED
|
@@ -53,6 +53,7 @@ from nautobot.core.forms.utils import (
|
|
|
53
53
|
from nautobot.core.forms.widgets import (
|
|
54
54
|
APISelect,
|
|
55
55
|
APISelectMultiple,
|
|
56
|
+
AutoPopulateWidget,
|
|
56
57
|
BulkEditNullBooleanSelect,
|
|
57
58
|
ColorSelect,
|
|
58
59
|
ContentTypeSelect,
|
|
@@ -102,6 +103,7 @@ __all__ = (
|
|
|
102
103
|
"APISelect",
|
|
103
104
|
"APISelectMultiple",
|
|
104
105
|
"AddressFieldMixin",
|
|
106
|
+
"AutoPopulateWidget",
|
|
105
107
|
"BootstrapMixin",
|
|
106
108
|
"BulkEditForm",
|
|
107
109
|
"BulkEditNullBooleanSelect",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{% extends 'circuits/providernetwork_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,57 +1,4 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{%
|
|
3
|
-
{% load helpers %}
|
|
4
|
-
{% load plugins %}
|
|
5
|
-
|
|
6
|
-
{% block breadcrumbs %}
|
|
7
|
-
<li><a href="{% url 'circuits:providernetwork_list' %}">Provider Networks</a></li>
|
|
2
|
+
{% block extra_breadcrumbs %}
|
|
8
3
|
<li><a href="{% url 'circuits:providernetwork_list' %}?provider={{ object.provider_id }}">{{ object.provider }}</a></li>
|
|
9
|
-
|
|
10
|
-
{% endblock %}
|
|
11
|
-
|
|
12
|
-
{% block content_left_page %}
|
|
13
|
-
<div class="panel panel-default">
|
|
14
|
-
<div class="panel-heading">
|
|
15
|
-
<strong>Provider Network</strong>
|
|
16
|
-
</div>
|
|
17
|
-
<table class="table table-hover panel-body attr-table">
|
|
18
|
-
<tr>
|
|
19
|
-
<td>Provider</td>
|
|
20
|
-
<td>{{ object.provider|hyperlinked_object }}</td>
|
|
21
|
-
</tr>
|
|
22
|
-
<tr>
|
|
23
|
-
<td>Name</td>
|
|
24
|
-
<td>{{ object.name }}</td>
|
|
25
|
-
</tr>
|
|
26
|
-
<tr>
|
|
27
|
-
<td>Description</td>
|
|
28
|
-
<td>{{ object.description }}</td>
|
|
29
|
-
</tr>
|
|
30
|
-
</table>
|
|
31
|
-
</div>
|
|
32
|
-
{% endblock content_left_page %}
|
|
33
|
-
|
|
34
|
-
{% block content_right_page %}
|
|
35
|
-
<div class="panel panel-default">
|
|
36
|
-
<div class="panel-heading">
|
|
37
|
-
<strong>Comments</strong>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="panel-body rendered-markdown">
|
|
40
|
-
{% if object.comments %}
|
|
41
|
-
{{ object.comments|render_markdown }}
|
|
42
|
-
{% else %}
|
|
43
|
-
<span class="text-muted">None</span>
|
|
44
|
-
{% endif %}
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
{% endblock content_right_page %}
|
|
48
|
-
|
|
49
|
-
{% block content_full_width_page %}
|
|
50
|
-
<div class="panel panel-default">
|
|
51
|
-
<div class="panel-heading">
|
|
52
|
-
<strong>Circuits</strong>
|
|
53
|
-
</div>
|
|
54
|
-
{% include 'inc/table.html' with table=circuits_table %}
|
|
55
|
-
</div>
|
|
56
|
-
{% include 'inc/paginator.html' with paginator=circuits_table.paginator page=circuits_table.page %}
|
|
57
|
-
{% endblock content_full_width_page %}
|
|
4
|
+
{% endblock extra_breadcrumbs %}
|
nautobot/circuits/views.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from django.contrib import messages
|
|
2
2
|
from django.db import transaction
|
|
3
|
-
from django.db.models import Q
|
|
4
3
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
5
4
|
from django.utils.html import format_html
|
|
6
5
|
from django_tables2 import RequestConfig
|
|
@@ -300,28 +299,26 @@ class ProviderNetworkUIViewSet(NautobotUIViewSet):
|
|
|
300
299
|
serializer_class = serializers.ProviderNetworkSerializer
|
|
301
300
|
table_class = tables.ProviderNetworkTable
|
|
302
301
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
.
|
|
313
|
-
.
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
context["circuits_table"] = circuits_table
|
|
324
|
-
return context
|
|
302
|
+
object_detail_content = ObjectDetailContent(
|
|
303
|
+
panels=(
|
|
304
|
+
ObjectFieldsPanel(
|
|
305
|
+
weight=100,
|
|
306
|
+
section=SectionChoices.LEFT_HALF,
|
|
307
|
+
fields="__all__",
|
|
308
|
+
),
|
|
309
|
+
ObjectsTablePanel(
|
|
310
|
+
weight=200,
|
|
311
|
+
section=SectionChoices.FULL_WIDTH,
|
|
312
|
+
table_class=tables.CircuitTable,
|
|
313
|
+
table_filter=["circuit_termination_a__provider_network", "circuit_termination_z__provider_network"],
|
|
314
|
+
prefetch_related_fields=["circuit_terminations__location"],
|
|
315
|
+
select_related_fields=["circuit_type", "tenant"],
|
|
316
|
+
exclude_columns=["provider_network", "circuit_termination_a", "circuit_termination_z"],
|
|
317
|
+
related_field_name="provider_network",
|
|
318
|
+
add_button_route=None,
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
)
|
|
325
322
|
|
|
326
323
|
|
|
327
324
|
class CircuitSwapTerminations(generic.ObjectEditView):
|
|
@@ -1,43 +1,5 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{% load helpers %}
|
|
3
|
-
|
|
4
2
|
{% block extra_breadcrumbs %}
|
|
5
|
-
|
|
3
|
+
<li><a href="{% url 'cloud:cloudaccount_list' %}?provider={{ object.provider.pk }}">{{ object.provider }}</a></li>
|
|
6
4
|
{% endblock extra_breadcrumbs %}
|
|
7
|
-
|
|
8
|
-
{% block content_left_page %}
|
|
9
|
-
<div class="panel panel-default">
|
|
10
|
-
<div class="panel-heading">
|
|
11
|
-
<strong>Cloud Account</strong>
|
|
12
|
-
</div>
|
|
13
|
-
<table class="table table-hover panel-body attr-table">
|
|
14
|
-
<tr>
|
|
15
|
-
<td>Name</td>
|
|
16
|
-
<td>
|
|
17
|
-
{{ object.name }}
|
|
18
|
-
</td>
|
|
19
|
-
</tr>
|
|
20
|
-
<tr>
|
|
21
|
-
<td>Provider</td>
|
|
22
|
-
<td>{{ object.provider|hyperlinked_object }}</td>
|
|
23
|
-
</tr>
|
|
24
|
-
<tr>
|
|
25
|
-
<td>Account Number</td>
|
|
26
|
-
<td>
|
|
27
|
-
<span class="hover_copy"><span id="copy_accountnumber">{{ object.account_number }}</span><button type="button" class="btn btn-inline btn-default hover_copy_button" data-clipboard-target="#copy_accountnumber">
|
|
28
|
-
<span class="mdi mdi-content-copy"></span>
|
|
29
|
-
</button>
|
|
30
|
-
</span>
|
|
31
|
-
</td>
|
|
32
|
-
</tr>
|
|
33
|
-
<tr>
|
|
34
|
-
<td>Secrets Group</td>
|
|
35
|
-
<td>{{ object.secrets_group|hyperlinked_object }}</td>
|
|
36
|
-
</tr>
|
|
37
|
-
<tr>
|
|
38
|
-
<td>Description</td>
|
|
39
|
-
<td>{{ object.description|placeholder }}</td>
|
|
40
|
-
</tr>
|
|
41
|
-
</table>
|
|
42
|
-
</div>
|
|
43
|
-
{% endblock content_left_page %}
|
|
5
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
nautobot/cloud/views.py
CHANGED
|
@@ -31,6 +31,8 @@ from nautobot.cloud.forms import (
|
|
|
31
31
|
)
|
|
32
32
|
from nautobot.cloud.models import CloudAccount, CloudNetwork, CloudResourceType, CloudService
|
|
33
33
|
from nautobot.cloud.tables import CloudAccountTable, CloudNetworkTable, CloudResourceTypeTable, CloudServiceTable
|
|
34
|
+
from nautobot.core.ui import object_detail
|
|
35
|
+
from nautobot.core.ui.choices import SectionChoices
|
|
34
36
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
35
37
|
from nautobot.core.views.viewsets import NautobotUIViewSet
|
|
36
38
|
from nautobot.ipam.tables import PrefixTable
|
|
@@ -45,6 +47,16 @@ class CloudAccountUIViewSet(NautobotUIViewSet):
|
|
|
45
47
|
table_class = CloudAccountTable
|
|
46
48
|
form_class = CloudAccountForm
|
|
47
49
|
|
|
50
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
51
|
+
panels=(
|
|
52
|
+
object_detail.ObjectFieldsPanel(
|
|
53
|
+
weight=100,
|
|
54
|
+
section=SectionChoices.LEFT_HALF,
|
|
55
|
+
fields="__all__",
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
48
60
|
|
|
49
61
|
class CloudNetworkUIViewSet(NautobotUIViewSet):
|
|
50
62
|
queryset = CloudNetwork.objects.all()
|
nautobot/core/api/mixins.py
CHANGED
|
@@ -109,6 +109,16 @@ class WritableSerializerMixin:
|
|
|
109
109
|
queryset = self.queryset
|
|
110
110
|
else:
|
|
111
111
|
queryset = self.Meta.model.objects
|
|
112
|
+
|
|
113
|
+
# Apply user permission on related objects
|
|
114
|
+
if (
|
|
115
|
+
"request" in self.context
|
|
116
|
+
and self.context["request"]
|
|
117
|
+
and self.context["request"].user
|
|
118
|
+
and hasattr(queryset, "restrict")
|
|
119
|
+
):
|
|
120
|
+
queryset = queryset.restrict(self.context["request"].user, "view")
|
|
121
|
+
|
|
112
122
|
if isinstance(data, list):
|
|
113
123
|
return [self.get_object(data=entry, queryset=queryset) for entry in data]
|
|
114
124
|
return self.get_object(data=data, queryset=queryset)
|
nautobot/core/api/urls.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from django.conf.urls import include
|
|
2
2
|
from django.urls import path
|
|
3
3
|
from drf_spectacular.views import (
|
|
4
|
-
SpectacularAPIView,
|
|
5
4
|
SpectacularJSONAPIView,
|
|
6
5
|
SpectacularYAMLAPIView,
|
|
7
6
|
)
|
|
@@ -12,6 +11,7 @@ from nautobot.core.api.views import (
|
|
|
12
11
|
GetFilterSetFieldDOMElementAPIView,
|
|
13
12
|
GetFilterSetFieldLookupExpressionChoicesAPIView,
|
|
14
13
|
GraphQLDRFAPIView,
|
|
14
|
+
NautobotSpectacularAPIView,
|
|
15
15
|
NautobotSpectacularRedocView,
|
|
16
16
|
NautobotSpectacularSwaggerView,
|
|
17
17
|
RenderJinjaView,
|
|
@@ -55,7 +55,7 @@ urlpatterns = [
|
|
|
55
55
|
path("docs/", NautobotSpectacularSwaggerView.as_view(url_name="schema"), name="api_docs"),
|
|
56
56
|
path("redoc/", NautobotSpectacularRedocView.as_view(url_name="schema"), name="api_redocs"),
|
|
57
57
|
path("settings-schema/", SettingsJSONSchemaView.as_view(), name="setting_schema_json"),
|
|
58
|
-
path("swagger/",
|
|
58
|
+
path("swagger/", NautobotSpectacularAPIView.as_view(), name="schema"),
|
|
59
59
|
path("swagger.json", SpectacularJSONAPIView.as_view(), name="schema_json"),
|
|
60
60
|
path("swagger.yaml", SpectacularYAMLAPIView.as_view(), name="schema_yaml"),
|
|
61
61
|
# GraphQL
|
nautobot/core/api/views.py
CHANGED
|
@@ -7,6 +7,7 @@ from django import __version__ as DJANGO_VERSION, forms
|
|
|
7
7
|
from django.apps import apps
|
|
8
8
|
from django.conf import settings
|
|
9
9
|
from django.contrib.contenttypes.models import ContentType
|
|
10
|
+
from django.core.cache import cache
|
|
10
11
|
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
|
|
11
12
|
from django.db import transaction
|
|
12
13
|
from django.db.models import ProtectedError
|
|
@@ -14,10 +15,12 @@ from django.db.models.fields.related import ForeignKey, ManyToManyField, Related
|
|
|
14
15
|
from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel
|
|
15
16
|
from django.http.response import HttpResponseBadRequest
|
|
16
17
|
from django.shortcuts import get_object_or_404, redirect
|
|
18
|
+
from django.utils.decorators import method_decorator
|
|
19
|
+
from django.views.decorators.gzip import gzip_page
|
|
17
20
|
from drf_spectacular.plumbing import get_relative_url, set_query_parameters
|
|
18
21
|
from drf_spectacular.renderers import OpenApiJsonRenderer
|
|
19
22
|
from drf_spectacular.utils import extend_schema
|
|
20
|
-
from drf_spectacular.views import SpectacularRedocView, SpectacularSwaggerView
|
|
23
|
+
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
|
21
24
|
from graphene_django.settings import graphene_settings
|
|
22
25
|
from graphene_django.views import GraphQLView, HttpError, instantiate_middleware
|
|
23
26
|
from graphql import get_default_backend
|
|
@@ -608,6 +611,41 @@ class NautobotSpectacularRedocView(APIVersioningGetSchemaURLMixin, SpectacularRe
|
|
|
608
611
|
"""Extend SpectacularRedocView to support Nautobot's ?api_version=<version> query parameter."""
|
|
609
612
|
|
|
610
613
|
|
|
614
|
+
@method_decorator(gzip_page, name="dispatch")
|
|
615
|
+
class NautobotSpectacularAPIView(SpectacularAPIView):
|
|
616
|
+
def _get_schema_response(self, request):
|
|
617
|
+
# version specified as parameter to the view always takes precedence. after
|
|
618
|
+
# that we try to source version through the schema view's own versioning_class.
|
|
619
|
+
version = self.api_version or request.version or self._get_version_parameter(request)
|
|
620
|
+
cache_key = f"openapi_schema_cache_{version}_{settings.VERSION}" # Invalidate cache on Nautobot release
|
|
621
|
+
etag = f'W/"{hash(cache_key)}"'
|
|
622
|
+
|
|
623
|
+
# With combined browser cache and backend cache, we have three options:
|
|
624
|
+
# - cache expired on browser, but Etag is the same (no changes in nautobot) -> 70-100ms response
|
|
625
|
+
# - cache expired on browser, Etag is different, cache present on backend -> 400-600ms response
|
|
626
|
+
# - cache expired on browser, Etag is different, no cache on backend -> 3-4s response
|
|
627
|
+
|
|
628
|
+
if_none_match = request.META.get("HTTP_IF_NONE_MATCH", "")
|
|
629
|
+
if if_none_match == etag:
|
|
630
|
+
return Response(status=304)
|
|
631
|
+
|
|
632
|
+
schema = cache.get(cache_key)
|
|
633
|
+
if not schema:
|
|
634
|
+
generator = self.generator_class(urlconf=self.urlconf, api_version=version, patterns=self.patterns)
|
|
635
|
+
schema = generator.get_schema(request=request, public=self.serve_public)
|
|
636
|
+
cache.set(cache_key, schema, 60 * 60 * 24 * 7)
|
|
637
|
+
|
|
638
|
+
return Response(
|
|
639
|
+
data=schema,
|
|
640
|
+
headers={
|
|
641
|
+
"Content-Disposition": f'inline; filename="{self._get_filename(request, version)}"',
|
|
642
|
+
"Cache-Control": f"max-age={3 * 24 * 60 * 60}, public",
|
|
643
|
+
"ETag": etag,
|
|
644
|
+
"Vary": "Accept, Accept-Encoding",
|
|
645
|
+
},
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
|
|
611
649
|
#
|
|
612
650
|
# GraphQL
|
|
613
651
|
#
|
nautobot/core/celery/encoders.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
from django.db import models
|
|
3
4
|
from rest_framework.utils.encoders import JSONEncoder
|
|
4
5
|
|
|
5
6
|
logger = logging.getLogger(__name__)
|
|
@@ -26,10 +27,9 @@ class NautobotKombuJSONEncoder(JSONEncoder):
|
|
|
26
27
|
def default(self, obj):
|
|
27
28
|
# Import here to avoid django.core.exceptions.ImproperlyConfigured Error.
|
|
28
29
|
# Core App is not set up yet if we import this at the top of the file.
|
|
29
|
-
from nautobot.core.models import BaseModel
|
|
30
30
|
from nautobot.core.models.managers import TagsManager
|
|
31
31
|
|
|
32
|
-
if isinstance(obj,
|
|
32
|
+
if isinstance(obj, models.Model):
|
|
33
33
|
cls = obj.__class__
|
|
34
34
|
module = cls.__module__
|
|
35
35
|
qual_name = ".".join([module, cls.__qualname__]) # fully qualified dotted import path
|
nautobot/core/forms/__init__.py
CHANGED
|
@@ -60,6 +60,7 @@ from nautobot.core.forms.utils import (
|
|
|
60
60
|
from nautobot.core.forms.widgets import (
|
|
61
61
|
APISelect,
|
|
62
62
|
APISelectMultiple,
|
|
63
|
+
AutoPopulateWidget,
|
|
63
64
|
BulkEditNullBooleanSelect,
|
|
64
65
|
ClearableFileInput,
|
|
65
66
|
ColorSelect,
|
|
@@ -86,6 +87,7 @@ __all__ = (
|
|
|
86
87
|
"APISelect",
|
|
87
88
|
"APISelectMultiple",
|
|
88
89
|
"AddressFieldMixin",
|
|
90
|
+
"AutoPopulateWidget",
|
|
89
91
|
"AutoPositionField",
|
|
90
92
|
"AutoPositionPatternField",
|
|
91
93
|
"BootstrapMixin",
|
nautobot/core/forms/fields.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import logging
|
|
2
3
|
import re
|
|
3
4
|
|
|
4
5
|
from django import forms as django_forms
|
|
@@ -11,6 +12,7 @@ from django.db.models import Q
|
|
|
11
12
|
from django.forms.fields import BoundField, CallableChoiceIterator, InvalidJSONInput, JSONField as _JSONField
|
|
12
13
|
from django.templatetags.static import static
|
|
13
14
|
from django.urls import reverse
|
|
15
|
+
from django.urls.exceptions import NoReverseMatch
|
|
14
16
|
from django.utils.html import format_html
|
|
15
17
|
import django_filters
|
|
16
18
|
from netaddr import EUI
|
|
@@ -21,6 +23,8 @@ from nautobot.core.forms import widgets
|
|
|
21
23
|
from nautobot.core.models import validators
|
|
22
24
|
from nautobot.core.utils import data as data_utils, lookup
|
|
23
25
|
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
24
28
|
__all__ = (
|
|
25
29
|
"CSVChoiceField",
|
|
26
30
|
"CSVContentTypeField",
|
|
@@ -453,7 +457,7 @@ class AutoPositionField(django_forms.CharField):
|
|
|
453
457
|
source (str, tuple): Name of the field (or a list of field names) that will be used to suggest a position.
|
|
454
458
|
"""
|
|
455
459
|
kwargs.setdefault("label", "Position")
|
|
456
|
-
kwargs.setdefault("widget", forms.
|
|
460
|
+
kwargs.setdefault("widget", forms.AutoPopulateWidget)
|
|
457
461
|
super().__init__(*args, **kwargs)
|
|
458
462
|
if isinstance(source, (tuple, list)):
|
|
459
463
|
source = " ".join(source)
|
|
@@ -469,7 +473,7 @@ class AutoPositionPatternField(ExpandableNameField):
|
|
|
469
473
|
source (str, tuple): Name pattern of the field (or a list of field names) that will be used to suggest a position pattern.
|
|
470
474
|
"""
|
|
471
475
|
kwargs.setdefault("label", "Position")
|
|
472
|
-
kwargs.setdefault("widget", forms.
|
|
476
|
+
kwargs.setdefault("widget", forms.AutoPopulateWidget(attrs={"title": "Regenerate position"}))
|
|
473
477
|
super().__init__(*args, **kwargs)
|
|
474
478
|
if isinstance(source, (tuple, list)):
|
|
475
479
|
source = " ".join(source)
|
|
@@ -591,8 +595,16 @@ class DynamicModelChoiceMixin:
|
|
|
591
595
|
widget = bound_field.field.widget
|
|
592
596
|
if not widget.attrs.get("data-url"):
|
|
593
597
|
route = lookup.get_route_for_model(self.queryset.model, "list", api=True)
|
|
594
|
-
|
|
595
|
-
|
|
598
|
+
try:
|
|
599
|
+
data_url = reverse(route)
|
|
600
|
+
widget.attrs["data-url"] = data_url
|
|
601
|
+
except NoReverseMatch:
|
|
602
|
+
logger.error(
|
|
603
|
+
'API route lookup "%s" failed for model %s, form field "%s" will not work properly',
|
|
604
|
+
route,
|
|
605
|
+
self.queryset.model.__name__,
|
|
606
|
+
bound_field.name,
|
|
607
|
+
)
|
|
596
608
|
|
|
597
609
|
return bound_field
|
|
598
610
|
|
|
@@ -800,9 +812,13 @@ class NumericArrayField(SimpleArrayField):
|
|
|
800
812
|
def to_python(self, value):
|
|
801
813
|
try:
|
|
802
814
|
if not value:
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
815
|
+
return []
|
|
816
|
+
|
|
817
|
+
if isinstance(value, list):
|
|
818
|
+
value = ",".join([str(n) for n in value])
|
|
819
|
+
|
|
820
|
+
value = ",".join([str(n) for n in forms.parse_numeric_range(value)])
|
|
821
|
+
|
|
806
822
|
except (TypeError, ValueError) as error:
|
|
807
823
|
raise ValidationError(error)
|
|
808
824
|
return super().to_python(value)
|
nautobot/core/forms/utils.py
CHANGED
|
@@ -41,6 +41,7 @@ def parse_numeric_range(input_string, base=10):
|
|
|
41
41
|
raise TypeError("Input value must be a string using a range format.")
|
|
42
42
|
except ValueError:
|
|
43
43
|
begin, end = dash_range, dash_range
|
|
44
|
+
|
|
44
45
|
begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1
|
|
45
46
|
values.extend(range(begin, end))
|
|
46
47
|
# Remove duplicates and sort
|
nautobot/core/forms/widgets.py
CHANGED
|
@@ -12,6 +12,7 @@ from nautobot.core.forms import utils
|
|
|
12
12
|
__all__ = (
|
|
13
13
|
"APISelect",
|
|
14
14
|
"APISelectMultiple",
|
|
15
|
+
"AutoPopulateWidget",
|
|
15
16
|
"BulkEditNullBooleanSelect",
|
|
16
17
|
"ClearableFileInput",
|
|
17
18
|
"ColorSelect",
|
|
@@ -41,6 +42,23 @@ class SlugWidget(forms.TextInput):
|
|
|
41
42
|
|
|
42
43
|
template_name = "widgets/sluginput.html"
|
|
43
44
|
|
|
45
|
+
def get_context(self, name, value, attrs):
|
|
46
|
+
custom_title = self.attrs.pop("title", None)
|
|
47
|
+
context = super().get_context(name, value, attrs)
|
|
48
|
+
context["widget"]["custom_title"] = custom_title
|
|
49
|
+
return context
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class AutoPopulateWidget(SlugWidget):
|
|
53
|
+
"""
|
|
54
|
+
Subclass SlugWidget and add support for auto-populate JavaScript logic from `form.js`.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def get_context(self, name, value, attrs):
|
|
58
|
+
attrs["data-autopopulate"] = ""
|
|
59
|
+
context = super().get_context(name, value, attrs)
|
|
60
|
+
return context
|
|
61
|
+
|
|
44
62
|
|
|
45
63
|
class ColorSelect(forms.Select):
|
|
46
64
|
"""
|
|
@@ -108,7 +108,7 @@ class BulkEditObjects(Job):
|
|
|
108
108
|
if form.cleaned_data[field_name]:
|
|
109
109
|
getattr(obj, field_name).set(form.cleaned_data[field_name])
|
|
110
110
|
# Normal fields
|
|
111
|
-
elif form.cleaned_data[field_name] not in (None, ""):
|
|
111
|
+
elif form.cleaned_data[field_name] not in (None, "", []):
|
|
112
112
|
setattr(obj, field_name, form.cleaned_data[field_name])
|
|
113
113
|
|
|
114
114
|
# Update custom fields
|
|
@@ -213,6 +213,7 @@ class Command(BaseCommand):
|
|
|
213
213
|
_create_batch(PlatformFactory, 20, description="with Manufacturers", has_manufacturer=True)
|
|
214
214
|
_create_batch(PlatformFactory, 5, description="without Manufacturers", has_manufacturer=False)
|
|
215
215
|
_create_batch(SoftwareVersionFactory, 20, description="to be usable by Devices")
|
|
216
|
+
_create_batch(ExternalIntegrationFactory, 20)
|
|
216
217
|
_create_batch(SoftwareImageFileFactory, 25, description="to be usable by DeviceTypes")
|
|
217
218
|
_create_batch(ManufacturerFactory, 4, description="without Platforms") # 4 more hard-coded Manufacturers
|
|
218
219
|
_create_batch(DeviceTypeFactory, 30)
|
|
@@ -312,7 +313,6 @@ class Command(BaseCommand):
|
|
|
312
313
|
has_pp_info=True,
|
|
313
314
|
has_description=True,
|
|
314
315
|
)
|
|
315
|
-
_create_batch(ExternalIntegrationFactory, 20)
|
|
316
316
|
_create_batch(ControllerFactory, 10, description="with Devices or DeviceRedundancyGroups")
|
|
317
317
|
_create_batch(ControllerManagedDeviceGroupFactory, 5, description="without any Devices")
|
|
318
318
|
_create_batch(SupportedDataRateFactory, 20)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from django.contrib.contenttypes.models import ContentType
|
|
2
2
|
from django.db import models
|
|
3
|
+
from django.utils.html import format_html
|
|
3
4
|
|
|
4
5
|
from nautobot.core.choices import ColorChoices
|
|
5
6
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
6
7
|
from nautobot.core.models import BaseManager, BaseModel, ContentTypeRelatedQuerySet
|
|
7
8
|
from nautobot.core.models.fields import ColorField
|
|
9
|
+
from nautobot.core.templatetags import helpers
|
|
8
10
|
from nautobot.extras.models.change_logging import ChangeLoggedModel
|
|
9
11
|
|
|
10
12
|
# Importing CustomFieldModel, ChangeLoggedModel, RelationshipModel from nautobot.extras.models
|
|
@@ -54,3 +56,10 @@ class NameColorContentTypesModel(
|
|
|
54
56
|
|
|
55
57
|
def get_content_types(self):
|
|
56
58
|
return ",".join(f"{ct.app_label}.{ct.model}" for ct in self.content_types.all())
|
|
59
|
+
|
|
60
|
+
def get_color_display(self):
|
|
61
|
+
if self.color:
|
|
62
|
+
return format_html(
|
|
63
|
+
'<span class="label color-block" style="background-color: #{}"> </span>', self.color
|
|
64
|
+
)
|
|
65
|
+
return helpers.placeholder(self.color)
|
|
@@ -27,8 +27,15 @@ class EnhancedURLValidator(URLValidator):
|
|
|
27
27
|
r"\Z",
|
|
28
28
|
re.IGNORECASE,
|
|
29
29
|
)
|
|
30
|
+
|
|
30
31
|
schemes = settings.ALLOWED_URL_SCHEMES
|
|
31
32
|
|
|
33
|
+
def __getattribute__(self, name):
|
|
34
|
+
"""Dynamically fetch schemes each time it's accessed."""
|
|
35
|
+
if name == "schemes":
|
|
36
|
+
self.schemes = settings.ALLOWED_URL_SCHEMES # Always return the latest list
|
|
37
|
+
return super().__getattribute__(name)
|
|
38
|
+
|
|
32
39
|
|
|
33
40
|
class ExclusionValidator(BaseValidator):
|
|
34
41
|
"""
|
nautobot/core/settings.py
CHANGED
|
@@ -287,20 +287,6 @@ TEST_USE_FACTORIES = is_truthy(os.getenv("NAUTOBOT_TEST_USE_FACTORIES", "False")
|
|
|
287
287
|
# Pseudo-random number generator seed, for reproducibility of test results.
|
|
288
288
|
TEST_FACTORY_SEED = os.getenv("NAUTOBOT_TEST_FACTORY_SEED", None)
|
|
289
289
|
|
|
290
|
-
#
|
|
291
|
-
# django-slowtests
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
# Performance test uses `NautobotPerformanceTestRunner` to run, which is only available once you have `django-slowtests` installed in your dev environment.
|
|
295
|
-
# `invoke performance-test` and adding `--performance-report` or `--performance-snapshot` at the end of the `invoke` command
|
|
296
|
-
# will automatically opt to NautobotPerformanceTestRunner to run the tests.
|
|
297
|
-
|
|
298
|
-
# The baseline file that the performance test is running against
|
|
299
|
-
# TODO we need to replace the baselines in this file with more consistent results at least for CI
|
|
300
|
-
TEST_PERFORMANCE_BASELINE_FILE = os.getenv(
|
|
301
|
-
"NAUTOBOT_TEST_PERFORMANCE_BASELINE_FILE", "nautobot/core/tests/performance_baselines.yml"
|
|
302
|
-
)
|
|
303
|
-
|
|
304
290
|
#
|
|
305
291
|
# Django Prometheus
|
|
306
292
|
#
|
nautobot/core/settings.yaml
CHANGED
|
@@ -1926,34 +1926,6 @@ properties:
|
|
|
1926
1926
|
version_added: "1.5.0"
|
|
1927
1927
|
see_also:
|
|
1928
1928
|
"`TEST_USE_FACTORIES`": "#test_use_factories"
|
|
1929
|
-
TEST_PERFORMANCE_BASELINE_FILE:
|
|
1930
|
-
default: "nautobot/core/tests/performance_baselines.yml"
|
|
1931
|
-
description: "File path of a YAML file providing baseline times for all performance-related tests."
|
|
1932
|
-
details: |-
|
|
1933
|
-
The YAML file should conform to the following format:
|
|
1934
|
-
|
|
1935
|
-
```yaml
|
|
1936
|
-
tests:
|
|
1937
|
-
- name: >-
|
|
1938
|
-
test_run_job_with_sensitive_variables_and_requires_approval
|
|
1939
|
-
(nautobot.extras.tests.test_views.JobTestCase)
|
|
1940
|
-
execution_time: 4.799533
|
|
1941
|
-
- name: test_run_missing_schedule (nautobot.extras.tests.test_views.JobTestCase)
|
|
1942
|
-
execution_time: 4.367563
|
|
1943
|
-
- name: test_run_now_missing_args (nautobot.extras.tests.test_views.JobTestCase)
|
|
1944
|
-
execution_time: 4.363194
|
|
1945
|
-
- name: >-
|
|
1946
|
-
test_create_object_with_constrained_permission
|
|
1947
|
-
(nautobot.extras.tests.test_views.GraphQLQueriesTestCase)
|
|
1948
|
-
execution_time: 3.474244
|
|
1949
|
-
- name: >-
|
|
1950
|
-
test_run_now_constrained_permissions
|
|
1951
|
-
(nautobot.extras.tests.test_views.JobTestCase)
|
|
1952
|
-
execution_time: 2.727531
|
|
1953
|
-
```
|
|
1954
|
-
environment_variable: "NAUTOBOT_TEST_PERFORMANCE_BASELINE_FILE"
|
|
1955
|
-
type: "string"
|
|
1956
|
-
version_added: "1.5.0"
|
|
1957
1929
|
TEST_USE_FACTORIES:
|
|
1958
1930
|
default: false
|
|
1959
1931
|
description: >-
|
nautobot/core/tables.py
CHANGED
|
@@ -493,6 +493,9 @@ class LinkedCountColumn(django_tables2.Column):
|
|
|
493
493
|
reverse_lookup (str, optional): The reverse lookup parameter to use to derive the count.
|
|
494
494
|
If not specified, the first key in `url_params` will be implicitly used as the `reverse_lookup` value.
|
|
495
495
|
distinct (bool, optional): Parameter passed through to `count_related()`.
|
|
496
|
+
display_field (str, optional): Name of the field to use when displaying an object rather than just a count.
|
|
497
|
+
This will be passed to hyperlinked_object() as the `field` parameter
|
|
498
|
+
If not specified, it will use the "display" field.
|
|
496
499
|
**kwargs (dict, optional): As the parent Column class.
|
|
497
500
|
|
|
498
501
|
Examples:
|
|
@@ -536,6 +539,7 @@ class LinkedCountColumn(django_tables2.Column):
|
|
|
536
539
|
reverse_lookup=None,
|
|
537
540
|
distinct=False,
|
|
538
541
|
default=None,
|
|
542
|
+
display_field="display",
|
|
539
543
|
**kwargs,
|
|
540
544
|
):
|
|
541
545
|
self.viewname = viewname
|
|
@@ -544,6 +548,7 @@ class LinkedCountColumn(django_tables2.Column):
|
|
|
544
548
|
self.url_params = url_params
|
|
545
549
|
self.reverse_lookup = reverse_lookup or next(iter(url_params.keys()))
|
|
546
550
|
self.distinct = distinct
|
|
551
|
+
self.display_field = display_field
|
|
547
552
|
self.model = get_model_for_view_name(self.viewname)
|
|
548
553
|
super().__init__(*args, default=default, **kwargs)
|
|
549
554
|
|
|
@@ -565,7 +570,7 @@ class LinkedCountColumn(django_tables2.Column):
|
|
|
565
570
|
if value > 1:
|
|
566
571
|
return format_html('<a href="{}" class="badge">{}</a>', url, value)
|
|
567
572
|
if related_record is not None:
|
|
568
|
-
return helpers.hyperlinked_object(related_record)
|
|
573
|
+
return helpers.hyperlinked_object(related_record, self.display_field)
|
|
569
574
|
if value == 1:
|
|
570
575
|
return format_html('<a href="{}" class="badge">{}</a>', url, value)
|
|
571
576
|
return helpers.placeholder(value)
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
{% if perms.extras.view_note %}
|
|
118
118
|
{% if active_tab != 'notes' and object.get_notes_url or active_tab == 'notes' %}
|
|
119
119
|
<li role="presentation"{% if active_tab == 'notes' %} class="active"{% endif %}>
|
|
120
|
-
<a href="{{ object.get_notes_url }}">Notes</a>
|
|
120
|
+
<a href="{{ object.get_notes_url }}">Notes {% badge object.notes.count %}</a>
|
|
121
121
|
</li>
|
|
122
122
|
{% endif %}
|
|
123
123
|
{% endif %}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<div class="input-group">
|
|
2
2
|
{% include "django/forms/widgets/input.html" %}
|
|
3
3
|
<span class="input-group-btn">
|
|
4
|
-
<button class="btn btn-default reslugify"
|
|
4
|
+
<button class="btn btn-default reslugify"
|
|
5
|
+
type="button"
|
|
6
|
+
title="{% if widget.custom_title %}{{ widget.custom_title }}{% else %}Regenerate slug{% endif %}"
|
|
7
|
+
data-regenerate="{{ widget.attrs.id }}"
|
|
8
|
+
>
|
|
5
9
|
<i class="mdi mdi-refresh"></i>
|
|
6
10
|
</button>
|
|
7
11
|
</span>
|