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/dcim/views.py
CHANGED
|
@@ -28,7 +28,6 @@ from rest_framework.exceptions import MethodNotAllowed
|
|
|
28
28
|
from rest_framework.response import Response
|
|
29
29
|
|
|
30
30
|
from nautobot.circuits.models import Circuit
|
|
31
|
-
from nautobot.cloud.models import CloudAccount
|
|
32
31
|
from nautobot.cloud.tables import CloudAccountTable
|
|
33
32
|
from nautobot.core.choices import ButtonColorChoices
|
|
34
33
|
from nautobot.core.exceptions import AbortTransaction
|
|
@@ -304,7 +303,7 @@ class LocationView(generic.ObjectView):
|
|
|
304
303
|
.select_related("parent", "location_type")
|
|
305
304
|
)
|
|
306
305
|
|
|
307
|
-
children_table = tables.LocationTable(children)
|
|
306
|
+
children_table = tables.LocationTable(children, hide_hierarchy_ui=True)
|
|
308
307
|
|
|
309
308
|
paginate = {
|
|
310
309
|
"paginator_class": EnhancedPaginator,
|
|
@@ -724,71 +723,40 @@ class RackReservationBulkDeleteView(generic.BulkDeleteView):
|
|
|
724
723
|
#
|
|
725
724
|
|
|
726
725
|
|
|
727
|
-
class
|
|
726
|
+
class ManufacturerUIViewSet(NautobotUIViewSet):
|
|
727
|
+
bulk_update_form_class = forms.ManufacturerBulkEditForm
|
|
728
|
+
filterset_class = filters.ManufacturerFilterSet
|
|
729
|
+
filterset_form_class = forms.ManufacturerFilterForm
|
|
730
|
+
form_class = forms.ManufacturerForm
|
|
731
|
+
serializer_class = serializers.ManufacturerSerializer
|
|
732
|
+
table_class = tables.ManufacturerTable
|
|
728
733
|
queryset = Manufacturer.objects.all()
|
|
729
|
-
filterset = filters.ManufacturerFilterSet
|
|
730
|
-
filterset_form = forms.ManufacturerFilterForm
|
|
731
|
-
table = tables.ManufacturerTable
|
|
732
734
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
.
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
)
|
|
759
|
-
|
|
760
|
-
cloud_account_table = CloudAccountTable(cloud_accounts)
|
|
761
|
-
paginate = {
|
|
762
|
-
"paginator_class": EnhancedPaginator,
|
|
763
|
-
"per_page": get_paginate_count(request),
|
|
764
|
-
}
|
|
765
|
-
RequestConfig(request, paginate).configure(cloud_account_table)
|
|
766
|
-
|
|
767
|
-
return {
|
|
768
|
-
"device_table": device_table,
|
|
769
|
-
"cloud_account_table": cloud_account_table,
|
|
770
|
-
**super().get_extra_context(request, instance),
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
class ManufacturerEditView(generic.ObjectEditView):
|
|
775
|
-
queryset = Manufacturer.objects.all()
|
|
776
|
-
model_form = forms.ManufacturerForm
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
class ManufacturerDeleteView(generic.ObjectDeleteView):
|
|
780
|
-
queryset = Manufacturer.objects.all()
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
class ManufacturerBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
|
|
784
|
-
queryset = Manufacturer.objects.all()
|
|
785
|
-
table = tables.ManufacturerTable
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
class ManufacturerBulkDeleteView(generic.BulkDeleteView):
|
|
789
|
-
queryset = Manufacturer.objects.all()
|
|
790
|
-
table = tables.ManufacturerTable
|
|
791
|
-
filterset = filters.ManufacturerFilterSet
|
|
735
|
+
# Object detail content with devices and cloud accounts related to the manufacturer
|
|
736
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
737
|
+
panels=(
|
|
738
|
+
object_detail.ObjectFieldsPanel(
|
|
739
|
+
weight=100,
|
|
740
|
+
section=SectionChoices.LEFT_HALF,
|
|
741
|
+
fields="__all__",
|
|
742
|
+
),
|
|
743
|
+
object_detail.ObjectsTablePanel(
|
|
744
|
+
weight=100,
|
|
745
|
+
section=SectionChoices.FULL_WIDTH,
|
|
746
|
+
table_class=tables.DeviceTable,
|
|
747
|
+
table_filter="device_type__manufacturer",
|
|
748
|
+
related_field_name="manufacturer",
|
|
749
|
+
exclude_columns=["manufacturer"],
|
|
750
|
+
),
|
|
751
|
+
object_detail.ObjectsTablePanel(
|
|
752
|
+
weight=100,
|
|
753
|
+
section=SectionChoices.FULL_WIDTH,
|
|
754
|
+
table_class=CloudAccountTable,
|
|
755
|
+
table_filter="provider",
|
|
756
|
+
exclude_columns=["provider"],
|
|
757
|
+
),
|
|
758
|
+
),
|
|
759
|
+
)
|
|
792
760
|
|
|
793
761
|
|
|
794
762
|
#
|
|
@@ -1769,6 +1737,7 @@ class DeviceView(generic.ObjectView):
|
|
|
1769
1737
|
weight=100,
|
|
1770
1738
|
color=ButtonColorChoices.BLUE,
|
|
1771
1739
|
label="Add Components",
|
|
1740
|
+
attributes={"id": "device-add-components-button"},
|
|
1772
1741
|
icon="mdi-plus-thick",
|
|
1773
1742
|
required_permissions=["dcim.change_device"],
|
|
1774
1743
|
children=(
|
|
@@ -3436,7 +3405,7 @@ class ModuleBayUIViewSet(ModuleBayCommonViewSetMixin, NautobotUIViewSet):
|
|
|
3436
3405
|
model_form_class = forms.ModuleBayForm
|
|
3437
3406
|
serializer_class = serializers.ModuleBaySerializer
|
|
3438
3407
|
table_class = tables.ModuleBayTable
|
|
3439
|
-
create_template_name = "dcim/
|
|
3408
|
+
create_template_name = "dcim/device_component_add.html"
|
|
3440
3409
|
|
|
3441
3410
|
def get_extra_context(self, request, instance):
|
|
3442
3411
|
if instance:
|
nautobot/extras/choices.py
CHANGED
|
@@ -488,6 +488,8 @@ class SecretsGroupSecretTypeChoices(ChoiceSet):
|
|
|
488
488
|
TYPE_SECRET = "secret" # noqa: S105 # hardcoded-password-string -- false positive
|
|
489
489
|
TYPE_TOKEN = "token" # noqa: S105 # hardcoded-password-string -- false positive
|
|
490
490
|
TYPE_USERNAME = "username"
|
|
491
|
+
TYPE_URL = "url"
|
|
492
|
+
TYPE_NOTES = "notes"
|
|
491
493
|
|
|
492
494
|
CHOICES = (
|
|
493
495
|
(TYPE_KEY, "Key"),
|
|
@@ -495,6 +497,8 @@ class SecretsGroupSecretTypeChoices(ChoiceSet):
|
|
|
495
497
|
(TYPE_SECRET, "Secret"),
|
|
496
498
|
(TYPE_TOKEN, "Token"),
|
|
497
499
|
(TYPE_USERNAME, "Username"),
|
|
500
|
+
(TYPE_URL, "URL"),
|
|
501
|
+
(TYPE_NOTES, "Notes"),
|
|
498
502
|
)
|
|
499
503
|
|
|
500
504
|
|
|
@@ -526,6 +526,12 @@ class ContactTeamFilterSet(NameSearchFilterSet, NautobotFilterSet):
|
|
|
526
526
|
|
|
527
527
|
|
|
528
528
|
class ContactFilterSet(ContactTeamFilterSet):
|
|
529
|
+
teams = NaturalKeyOrPKMultipleChoiceFilter(
|
|
530
|
+
queryset=Team.objects.all(),
|
|
531
|
+
to_field_name="name",
|
|
532
|
+
label="Team (name or ID)",
|
|
533
|
+
)
|
|
534
|
+
|
|
529
535
|
class Meta:
|
|
530
536
|
model = Contact
|
|
531
537
|
fields = "__all__"
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -142,6 +142,7 @@ __all__ = (
|
|
|
142
142
|
"DynamicGroupFilterForm",
|
|
143
143
|
"DynamicGroupForm",
|
|
144
144
|
"DynamicGroupMembershipFormSet",
|
|
145
|
+
"ExportTemplateBulkEditForm",
|
|
145
146
|
"ExportTemplateFilterForm",
|
|
146
147
|
"ExportTemplateForm",
|
|
147
148
|
"ExternalIntegrationBulkEditForm",
|
|
@@ -180,6 +181,7 @@ __all__ = (
|
|
|
180
181
|
"ObjectMetadataFilterForm",
|
|
181
182
|
"PasswordInputWithPlaceholder",
|
|
182
183
|
"RelationshipAssociationFilterForm",
|
|
184
|
+
"RelationshipBulkEditForm",
|
|
183
185
|
"RelationshipFilterForm",
|
|
184
186
|
"RelationshipForm",
|
|
185
187
|
"RoleBulkEditForm",
|
|
@@ -519,10 +521,11 @@ class CustomFieldBulkDeleteForm(ConfirmationForm):
|
|
|
519
521
|
else:
|
|
520
522
|
context = change_context.as_dict(queryset)
|
|
521
523
|
context["context_detail"] = "bulk delete custom field data"
|
|
522
|
-
tasks = [
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
524
|
+
tasks = []
|
|
525
|
+
for obj in queryset:
|
|
526
|
+
pk_set = set(obj.content_types.values_list("pk", flat=True))
|
|
527
|
+
if pk_set:
|
|
528
|
+
tasks.append(delete_custom_field_data.si(obj.key, pk_set, context))
|
|
526
529
|
return tasks
|
|
527
530
|
|
|
528
531
|
def perform_pre_delete(self, queryset):
|
|
@@ -533,10 +536,11 @@ class CustomFieldBulkDeleteForm(ConfirmationForm):
|
|
|
533
536
|
logger.error("Celery worker process not running. Object custom fields may fail to reflect this deletion.")
|
|
534
537
|
return
|
|
535
538
|
tasks = self.construct_custom_field_delete_tasks(queryset)
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
539
|
+
if tasks:
|
|
540
|
+
# Executing the tasks in the background sequentially using chain() aligns with how a single
|
|
541
|
+
# CustomField object is deleted. We decided to not check the result because it needs at least one worker
|
|
542
|
+
# to be active and comes with extra performance penalty.
|
|
543
|
+
chain(*tasks).apply_async()
|
|
540
544
|
|
|
541
545
|
|
|
542
546
|
#
|
|
@@ -749,6 +753,31 @@ class StaticGroupAssociationFilterForm(NautobotFilterForm):
|
|
|
749
753
|
#
|
|
750
754
|
# Export Templates
|
|
751
755
|
#
|
|
756
|
+
class ExportTemplateBulkEditForm(NautobotBulkEditForm):
|
|
757
|
+
pk = forms.ModelMultipleChoiceField(queryset=ExportTemplate.objects.all(), widget=forms.MultipleHiddenInput())
|
|
758
|
+
|
|
759
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
760
|
+
mime_type = forms.CharField(
|
|
761
|
+
max_length=CHARFIELD_MAX_LENGTH,
|
|
762
|
+
required=False,
|
|
763
|
+
label="MIME type",
|
|
764
|
+
help_text="Defaults to <code>text/plain</code>",
|
|
765
|
+
)
|
|
766
|
+
file_extension = forms.CharField(
|
|
767
|
+
max_length=CHARFIELD_MAX_LENGTH, required=False, help_text="Extension to append to the rendered filename"
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
content_type = forms.ModelChoiceField(
|
|
771
|
+
queryset=ContentType.objects.filter(FeatureQuery("export_templates").get_query()).order_by(
|
|
772
|
+
"app_label", "model"
|
|
773
|
+
),
|
|
774
|
+
required=False,
|
|
775
|
+
label="Content Type",
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
class Meta:
|
|
779
|
+
model = ExportTemplate
|
|
780
|
+
nullable_fields = ["description", "mime_type", "file_extension"]
|
|
752
781
|
|
|
753
782
|
|
|
754
783
|
class ExportTemplateForm(BootstrapMixin, forms.ModelForm):
|
|
@@ -1774,6 +1803,45 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
|
|
|
1774
1803
|
#
|
|
1775
1804
|
|
|
1776
1805
|
|
|
1806
|
+
class RelationshipBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditFormMixin, NoteModelBulkEditFormMixin):
|
|
1807
|
+
pk = forms.ModelMultipleChoiceField(queryset=Relationship.objects.all(), widget=forms.MultipleHiddenInput())
|
|
1808
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1809
|
+
type = forms.ChoiceField(
|
|
1810
|
+
required=False,
|
|
1811
|
+
label="type",
|
|
1812
|
+
choices=add_blank_choice(RelationshipTypeChoices),
|
|
1813
|
+
)
|
|
1814
|
+
source_hidden = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect)
|
|
1815
|
+
destination_hidden = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect)
|
|
1816
|
+
source_filter = forms.JSONField(required=False, widget=forms.Textarea, help_text="Filter for the source")
|
|
1817
|
+
destination_filter = forms.JSONField(required=False, widget=forms.Textarea, help_text="Filter for the destination")
|
|
1818
|
+
source_type = CSVContentTypeField(
|
|
1819
|
+
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()), required=False
|
|
1820
|
+
)
|
|
1821
|
+
destination_type = CSVContentTypeField(
|
|
1822
|
+
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()), required=False
|
|
1823
|
+
)
|
|
1824
|
+
source_label = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1825
|
+
destination_label = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1826
|
+
advanced_ui = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect)
|
|
1827
|
+
|
|
1828
|
+
class Meta:
|
|
1829
|
+
model = Relationship
|
|
1830
|
+
fields = [
|
|
1831
|
+
"description",
|
|
1832
|
+
"type",
|
|
1833
|
+
"source_hidden",
|
|
1834
|
+
"destination_hidden",
|
|
1835
|
+
"source_filter",
|
|
1836
|
+
"destination_filter",
|
|
1837
|
+
"source_type",
|
|
1838
|
+
"destination_type",
|
|
1839
|
+
"source_label",
|
|
1840
|
+
"destination_label",
|
|
1841
|
+
"advanced_ui",
|
|
1842
|
+
]
|
|
1843
|
+
|
|
1844
|
+
|
|
1777
1845
|
class RelationshipForm(BootstrapMixin, forms.ModelForm):
|
|
1778
1846
|
key = SlugField(
|
|
1779
1847
|
help_text="Internal name of this relationship. Please use underscores rather than dashes.",
|
|
@@ -1891,8 +1959,11 @@ class RoleBulkEditForm(NautobotBulkEditForm):
|
|
|
1891
1959
|
color = forms.CharField(max_length=6, required=False, widget=ColorSelect())
|
|
1892
1960
|
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1893
1961
|
weight = forms.IntegerField(required=False)
|
|
1894
|
-
|
|
1895
|
-
queryset=RoleModelsQuery().as_queryset(), required=False, label="Content Type(s)"
|
|
1962
|
+
add_content_types = MultipleContentTypeField(
|
|
1963
|
+
queryset=RoleModelsQuery().as_queryset(), required=False, label="Add Content Type(s)"
|
|
1964
|
+
)
|
|
1965
|
+
remove_content_types = MultipleContentTypeField(
|
|
1966
|
+
queryset=RoleModelsQuery().as_queryset(), required=False, label="Remove Content Type(s)"
|
|
1896
1967
|
)
|
|
1897
1968
|
|
|
1898
1969
|
class Meta:
|
|
@@ -2012,7 +2083,8 @@ class StatusBulkEditForm(NautobotBulkEditForm):
|
|
|
2012
2083
|
|
|
2013
2084
|
pk = forms.ModelMultipleChoiceField(queryset=Status.objects.all(), widget=forms.MultipleHiddenInput)
|
|
2014
2085
|
color = forms.CharField(max_length=6, required=False, widget=ColorSelect())
|
|
2015
|
-
|
|
2086
|
+
add_content_types = MultipleContentTypeField(feature="statuses", required=False, label="Add Content Type(s)")
|
|
2087
|
+
remove_content_types = MultipleContentTypeField(feature="statuses", required=False, label="Remove Content Type(s)")
|
|
2016
2088
|
|
|
2017
2089
|
class Meta:
|
|
2018
2090
|
nullable_fields = []
|
|
@@ -822,16 +822,17 @@ class CustomField(
|
|
|
822
822
|
|
|
823
823
|
super().delete(*args, **kwargs)
|
|
824
824
|
|
|
825
|
-
|
|
826
|
-
|
|
825
|
+
if content_types:
|
|
826
|
+
# Circular Import
|
|
827
|
+
from nautobot.extras.signals import change_context_state
|
|
827
828
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
829
|
+
change_context = change_context_state.get()
|
|
830
|
+
if change_context is None:
|
|
831
|
+
context = None
|
|
832
|
+
else:
|
|
833
|
+
context = change_context.as_dict(instance=self)
|
|
834
|
+
context["context_detail"] = "delete custom field data"
|
|
835
|
+
delete_custom_field_data.delay(self.key, content_types, context)
|
|
835
836
|
|
|
836
837
|
def add_prefix_to_cf_key(self):
|
|
837
838
|
return "cf_" + str(self.key)
|
|
@@ -94,6 +94,24 @@
|
|
|
94
94
|
"availability": "Open Source"
|
|
95
95
|
"icon": >-
|
|
96
96
|
data:image/png;base64,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
|
|
97
|
+
- "name": "DNS Models"
|
|
98
|
+
"use_cases":
|
|
99
|
+
- "DNS"
|
|
100
|
+
"requires": []
|
|
101
|
+
"docs": "https://docs.nautobot.com/projects/dns-models/en/latest/"
|
|
102
|
+
"headline": "Model DNS Zones and their associated records in a vendor-neutral manner."
|
|
103
|
+
"description": >-
|
|
104
|
+
DNS Models allows users to document and understand the network by modeling their DNS data. DNS Records can then
|
|
105
|
+
be directly related to data about the network.
|
|
106
|
+
"package_name": "nautobot_dns_models"
|
|
107
|
+
"author": "Network to Code (NTC)"
|
|
108
|
+
"display":
|
|
109
|
+
"cloud": true
|
|
110
|
+
"oss": true
|
|
111
|
+
"enterprise": true
|
|
112
|
+
"availability": "Open Source"
|
|
113
|
+
"icon": >-
|
|
114
|
+
data:image/png;base64,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
|
|
97
115
|
- "name": "Data Validation Engine"
|
|
98
116
|
"use_cases":
|
|
99
117
|
- "Data Management"
|
nautobot/extras/signals.py
CHANGED
|
@@ -125,6 +125,17 @@ def invalidate_relationship_models_cache(sender, **kwargs):
|
|
|
125
125
|
cache.delete_pattern(f"{method.cache_key_prefix}.*")
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
@receiver(post_save, sender=CustomField)
|
|
129
|
+
@receiver(post_delete, sender=CustomField)
|
|
130
|
+
@receiver(post_save, sender=Relationship)
|
|
131
|
+
@receiver(m2m_changed, sender=Relationship)
|
|
132
|
+
@receiver(post_delete, sender=Relationship)
|
|
133
|
+
def invalidate_openapi_schema_cache(sender, **kwargs):
|
|
134
|
+
"""Invalidate the openapi schema cache."""
|
|
135
|
+
with contextlib.suppress(redis.exceptions.ConnectionError):
|
|
136
|
+
cache.delete_pattern("openapi_schema_cache_*")
|
|
137
|
+
|
|
138
|
+
|
|
128
139
|
@receiver(post_save)
|
|
129
140
|
@receiver(m2m_changed)
|
|
130
141
|
def _handle_changed_object(sender, instance, raw=False, **kwargs):
|
|
@@ -327,7 +338,9 @@ def post_migrate_clear_content_type_caches(sender, app_config, signal, **kwargs)
|
|
|
327
338
|
|
|
328
339
|
def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
|
|
329
340
|
"""
|
|
330
|
-
Handle
|
|
341
|
+
Handle provisioning/deprovisioning of custom_field_data when there are changes to CustomField.content_types.
|
|
342
|
+
|
|
343
|
+
The name of this function is misleading as this signal applies to *added* content-types as well.
|
|
331
344
|
"""
|
|
332
345
|
|
|
333
346
|
change_context = change_context_state.get()
|
|
@@ -335,13 +348,39 @@ def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
|
|
|
335
348
|
context = None
|
|
336
349
|
else:
|
|
337
350
|
context = change_context.as_dict(instance=instance)
|
|
338
|
-
|
|
339
|
-
|
|
351
|
+
|
|
352
|
+
if action == "pre_remove":
|
|
353
|
+
# Existing content types may be removed from the custom field, delete their data if so.
|
|
354
|
+
# CAUTION: pk_set in this _remove case is the content-types that were *requested* to remove,
|
|
355
|
+
# **not** the content-types that actually *will need to be* removed. In other words, this is not idempotent:
|
|
356
|
+
# my_cf.content_types.remove(device_ct) --> pk_set = {device_ct.pk}
|
|
357
|
+
# my_cf.content_types.remove(device_ct) --> pk_set = {device_ct.pk} again even though it was already gone
|
|
358
|
+
# So we need to check which content types will actually be removed to not create unnecessary tasks:
|
|
359
|
+
removed_pk_set = pk_set.intersection(instance.content_types.values_list("pk", flat=True))
|
|
360
|
+
if not removed_pk_set:
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
if context:
|
|
364
|
+
context["context_detail"] = "delete custom field data from existing content types"
|
|
365
|
+
transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, removed_pk_set, context))
|
|
366
|
+
|
|
367
|
+
elif action == "pre_clear":
|
|
368
|
+
# In this case, the provided pk_set is always empty, so we need to look at the current values instead:
|
|
369
|
+
cleared_pk_set = set(instance.content_types.values_list("pk", flat=True))
|
|
370
|
+
if not cleared_pk_set:
|
|
371
|
+
return
|
|
372
|
+
|
|
340
373
|
if context:
|
|
341
374
|
context["context_detail"] = "delete custom field data from existing content types"
|
|
342
|
-
transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key,
|
|
375
|
+
transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, cleared_pk_set, context))
|
|
343
376
|
|
|
344
377
|
elif action == "post_add":
|
|
378
|
+
# Unlike the above _remove case, in the _add case pk_set is the *new* content-types only,
|
|
379
|
+
# and for whatever reason, Django triggers this signal even if there was no actual change.
|
|
380
|
+
# To avoid creating unnecessary background tasks, we need to check for this case ourselves:
|
|
381
|
+
if not pk_set:
|
|
382
|
+
return
|
|
383
|
+
|
|
345
384
|
# New content types have been added to the custom field, provision them
|
|
346
385
|
if context:
|
|
347
386
|
context["context_detail"] = "provision custom field data for new content types"
|
nautobot/extras/tables.py
CHANGED
|
@@ -1063,14 +1063,13 @@ class ObjectMetadataTable(BaseTable):
|
|
|
1063
1063
|
|
|
1064
1064
|
class NoteTable(BaseTable):
|
|
1065
1065
|
actions = ButtonsColumn(Note)
|
|
1066
|
-
created = tables.
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
)
|
|
1066
|
+
created = tables.DateTimeColumn(linkify=True)
|
|
1067
|
+
last_updated = tables.DateTimeColumn()
|
|
1068
|
+
note = tables.Column()
|
|
1070
1069
|
|
|
1071
1070
|
class Meta(BaseTable.Meta):
|
|
1072
1071
|
model = Note
|
|
1073
|
-
fields = ("created", "note", "user_name")
|
|
1072
|
+
fields = ("created", "last_updated", "note", "user_name")
|
|
1074
1073
|
|
|
1075
1074
|
def render_note(self, value):
|
|
1076
1075
|
return render_markdown(value)
|
nautobot/extras/tasks.py
CHANGED
|
@@ -121,12 +121,13 @@ def delete_custom_field_data(field_key, content_type_pk_set, change_context=None
|
|
|
121
121
|
for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
|
|
122
122
|
model = ct.model_class()
|
|
123
123
|
queryset = model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False})
|
|
124
|
+
pk_list = []
|
|
124
125
|
if change_context is not None:
|
|
125
126
|
pk_list = list(queryset.values_list("pk", flat=True))
|
|
126
127
|
task_logger.info("Deleting existing values for custom field `%s` from %s records...", field_key, ct.model)
|
|
127
128
|
count = queryset.update(_custom_field_data=JSONRemove("_custom_field_data", field_key))
|
|
128
129
|
task_logger.info("Updated %d records", count)
|
|
129
|
-
if change_context is not None:
|
|
130
|
+
if count and change_context is not None:
|
|
130
131
|
# Since we used update() above, we bypassed ObjectChange automatic creation via signals. Create them now
|
|
131
132
|
_generate_bulk_object_changes(change_context, model.objects.filter(pk__in=pk_list), task_logger)
|
|
132
133
|
|
|
@@ -155,6 +156,7 @@ def provision_field(field_id, content_type_pk_set, change_context=None):
|
|
|
155
156
|
for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
|
|
156
157
|
model = ct.model_class()
|
|
157
158
|
queryset = model.objects.filter(**{f"_custom_field_data__{field.key}__isnull": True})
|
|
159
|
+
pk_list = []
|
|
158
160
|
if change_context is not None:
|
|
159
161
|
pk_list = list(queryset.values_list("pk", flat=True))
|
|
160
162
|
task_logger.info(
|
|
@@ -165,7 +167,7 @@ def provision_field(field_id, content_type_pk_set, change_context=None):
|
|
|
165
167
|
)
|
|
166
168
|
count = queryset.update(_custom_field_data=JSONSet("_custom_field_data", field.key, field.default))
|
|
167
169
|
task_logger.info("Updated %d records.", count)
|
|
168
|
-
if change_context is not None:
|
|
170
|
+
if count and change_context is not None:
|
|
169
171
|
# Since we used update() above, we bypassed ObjectChange automatic creation via signals. Create them now
|
|
170
172
|
_generate_bulk_object_changes(change_context, model.objects.filter(pk__in=pk_list), task_logger)
|
|
171
173
|
|
|
@@ -1,59 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{%
|
|
3
|
-
|
|
4
|
-
{% block content_left_page %}
|
|
5
|
-
<div class="panel panel-default">
|
|
6
|
-
<div class="panel-heading">
|
|
7
|
-
<strong>Contact</strong>
|
|
8
|
-
</div>
|
|
9
|
-
<table class="table table-hover panel-body attr-table">
|
|
10
|
-
<tr>
|
|
11
|
-
<td>Name</td>
|
|
12
|
-
<td>{{ object.name }}</td>
|
|
13
|
-
</tr>
|
|
14
|
-
<tr>
|
|
15
|
-
<td>Phone</td>
|
|
16
|
-
<td>{{ object.phone|hyperlinked_phone_number }}</td>
|
|
17
|
-
</tr>
|
|
18
|
-
<tr>
|
|
19
|
-
<td>E-mail</td>
|
|
20
|
-
<td>{{ object.email|hyperlinked_email }}</td>
|
|
21
|
-
</tr>
|
|
22
|
-
<tr>
|
|
23
|
-
<td>Address</td>
|
|
24
|
-
<td>
|
|
25
|
-
{% if object.address %}
|
|
26
|
-
<div class="pull-right noprint">
|
|
27
|
-
<a href="https://maps.google.com/?q={{ object.address|urlencode }}" target="_blank" class="btn btn-primary btn-xs">
|
|
28
|
-
<i class="mdi mdi-map-marker"></i> Map it
|
|
29
|
-
</a>
|
|
30
|
-
</div>
|
|
31
|
-
<span>{{ object.address|linebreaksbr }}</span>
|
|
32
|
-
{% else %}
|
|
33
|
-
<span class="text-muted">—</span>
|
|
34
|
-
{% endif %}
|
|
35
|
-
</td>
|
|
36
|
-
</tr>
|
|
37
|
-
</table>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="panel panel-default">
|
|
40
|
-
<div class="panel-heading">
|
|
41
|
-
<strong>Comments</strong>
|
|
42
|
-
</div>
|
|
43
|
-
<div class="panel-body rendered-markdown">
|
|
44
|
-
{% if object.comments %}
|
|
45
|
-
{{ object.comments|render_markdown }}
|
|
46
|
-
{% else %}
|
|
47
|
-
<span class="text-muted">None</span>
|
|
48
|
-
{% endif %}
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
{% endblock %}
|
|
52
|
-
|
|
53
|
-
{% block content_right_page %}
|
|
54
|
-
{% include 'panel_table.html' with table=teams_table heading='Assigned Teams' %}
|
|
55
|
-
{% endblock %}
|
|
56
|
-
|
|
57
|
-
{% block content_full_width_page %}
|
|
58
|
-
{% include 'panel_table.html' with table=contact_associations_table heading='Contact For' %}
|
|
59
|
-
{% endblock %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,54 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{%
|
|
3
|
-
|
|
4
|
-
{% block content_left_page %}
|
|
5
|
-
<div class="panel panel-default">
|
|
6
|
-
<div class="panel-heading">
|
|
7
|
-
<strong>Details</strong>
|
|
8
|
-
</div>
|
|
9
|
-
|
|
10
|
-
<table class="table table-hover panel-body attr-table">
|
|
11
|
-
<tr>
|
|
12
|
-
<td>Name</td>
|
|
13
|
-
<td><span>{{ object.name }}</span></td>
|
|
14
|
-
</tr>
|
|
15
|
-
<tr>
|
|
16
|
-
<td>Owner</td>
|
|
17
|
-
<td>{{ object.owner|hyperlinked_object }}</td>
|
|
18
|
-
</tr>
|
|
19
|
-
<tr>
|
|
20
|
-
<td>Description</td>
|
|
21
|
-
<td>{{ object.description|placeholder }}</td>
|
|
22
|
-
</tr>
|
|
23
|
-
</table>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div class="panel panel-default">
|
|
27
|
-
<div class="panel-heading">
|
|
28
|
-
<strong>Template</strong>
|
|
29
|
-
</div>
|
|
30
|
-
<table class="table table-hover panel-body attr-table">
|
|
31
|
-
<tr>
|
|
32
|
-
<td>Object Type</td>
|
|
33
|
-
<td><span>{{ object.content_type }}</span></td>
|
|
34
|
-
</tr>
|
|
35
|
-
<tr>
|
|
36
|
-
<td>Mime Type</td>
|
|
37
|
-
<td><span>{{ object.mime_type }}</span></td>
|
|
38
|
-
</tr>
|
|
39
|
-
<tr>
|
|
40
|
-
<td>File Extension</td>
|
|
41
|
-
<td><span>{{ object.file_extension }}</span></td>
|
|
42
|
-
</tr>
|
|
43
|
-
</table>
|
|
44
|
-
</div>
|
|
45
|
-
{% endblock content_left_page %}
|
|
46
|
-
|
|
47
|
-
{% block content_right_page %}
|
|
48
|
-
<div class="panel panel-default">
|
|
49
|
-
<div class="panel-heading">
|
|
50
|
-
<strong>Code Template</strong>
|
|
51
|
-
</div>
|
|
52
|
-
{% if object.template_code %} <pre>{{ object.template_code }}</pre> {% else %} {{ None }} {% endif %}
|
|
53
|
-
</div>
|
|
54
|
-
{% endblock content_right_page %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<br />
|
|
22
22
|
<small>
|
|
23
23
|
<span class="text-muted">{{ change.user_name }} -</span>
|
|
24
|
-
<a href="{{ change.get_absolute_url }}" class="text-muted">{{ change.time|date:
|
|
24
|
+
<a href="{{ change.get_absolute_url }}" class="text-muted">{{ change.time|date:settings.SHORT_DATETIME_FORMAT }}</a>
|
|
25
25
|
</small>
|
|
26
26
|
</div>
|
|
27
27
|
{% endwith %}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<span class="pull-right" title="{{ result.date_created }}">{% include 'extras/inc/job_label.html' %}</span>
|
|
8
8
|
<br>
|
|
9
9
|
<small>
|
|
10
|
-
<span class="text-muted">{{ result.user }} - {{ result.date_done|date:
|
|
10
|
+
<span class="text-muted">{{ result.user }} - {{ result.date_done|date:settings.SHORT_DATETIME_FORMAT }}</span>
|
|
11
11
|
</small>
|
|
12
12
|
</div>
|
|
13
13
|
{% if forloop.last %}
|