nautobot 2.4.14__py3-none-any.whl → 2.4.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/choices.py +8 -0
- nautobot/apps/ui.py +14 -0
- nautobot/core/api/views.py +2 -0
- nautobot/core/choices.py +4 -0
- nautobot/core/filters.py +21 -41
- nautobot/core/management/commands/check_job_approval_status.py +47 -0
- nautobot/core/management/commands/generate_test_data.py +1 -1
- nautobot/core/management/commands/migrate.py +1 -1
- nautobot/core/models/tree_queries.py +17 -0
- nautobot/core/settings.py +2 -2
- nautobot/core/tables.py +25 -2
- nautobot/core/templates/base_django.html +1 -1
- nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
- nautobot/core/templates/generic/object_list.html +17 -20
- nautobot/core/templates/inc/breadcrumbs.html +14 -0
- nautobot/core/templatetags/buttons.py +2 -4
- nautobot/core/templatetags/helpers.py +29 -6
- nautobot/core/templatetags/ui_framework.py +21 -0
- nautobot/core/testing/filters.py +20 -3
- nautobot/core/testing/forms.py +1 -1
- nautobot/core/tests/integration/test_filters.py +2 -2
- nautobot/core/tests/test_breadcrumbs.py +366 -0
- nautobot/core/tests/test_commands.py +40 -0
- nautobot/core/tests/test_filters.py +51 -1
- nautobot/core/tests/test_forms.py +1 -1
- nautobot/core/tests/test_graphql.py +4 -4
- nautobot/core/tests/test_titles.py +183 -0
- nautobot/core/tests/test_tree_queries.py +30 -0
- nautobot/core/tests/test_views.py +2 -2
- nautobot/core/tests/test_views_utils.py +1 -1
- nautobot/core/ui/breadcrumbs.py +538 -0
- nautobot/core/ui/bulk_buttons.py +53 -0
- nautobot/core/ui/object_detail.py +31 -8
- nautobot/core/ui/titles.py +127 -0
- nautobot/core/ui/utils.py +25 -0
- nautobot/core/utils/migrations.py +1 -1
- nautobot/core/views/__init__.py +1 -1
- nautobot/core/views/mixins.py +26 -1
- nautobot/core/views/renderers.py +20 -2
- nautobot/core/views/utils.py +13 -12
- nautobot/dcim/api/serializers.py +9 -0
- nautobot/dcim/choices.py +53 -0
- nautobot/dcim/filters/__init__.py +15 -3
- nautobot/dcim/forms.py +120 -7
- nautobot/dcim/management/commands/trace_paths.py +1 -1
- nautobot/dcim/migrations/0072_alter_powerfeed_options_and_more.py +97 -0
- nautobot/dcim/models/device_component_templates.py +8 -0
- nautobot/dcim/models/device_components.py +31 -12
- nautobot/dcim/models/devices.py +1 -1
- nautobot/dcim/models/power.py +171 -10
- nautobot/dcim/models/racks.py +7 -4
- nautobot/dcim/tables/devices.py +2 -0
- nautobot/dcim/tables/devicetypes.py +1 -0
- nautobot/dcim/tables/power.py +30 -2
- nautobot/dcim/templates/dcim/device.html +2 -2
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -214
- nautobot/dcim/templates/dcim/location_retrieve.html +2 -2
- nautobot/dcim/templates/dcim/powerfeed_edit.html +8 -0
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -1
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +61 -0
- nautobot/dcim/tests/test_api.py +24 -4
- nautobot/dcim/tests/test_filters.py +91 -13
- nautobot/dcim/tests/test_models.py +262 -0
- nautobot/dcim/tests/test_views.py +20 -12
- nautobot/dcim/utils.py +9 -0
- nautobot/dcim/views.py +390 -77
- nautobot/extras/factory.py +19 -20
- nautobot/extras/filters/__init__.py +3 -2
- nautobot/extras/filters/mixins.py +15 -1
- nautobot/extras/forms/__init__.py +2 -1
- nautobot/extras/forms/forms.py +62 -0
- nautobot/extras/managers.py +4 -1
- nautobot/extras/migrations/0125_jobresult_date_started.py +18 -0
- nautobot/extras/models/customfields.py +1 -2
- nautobot/extras/models/datasources.py +1 -2
- nautobot/extras/models/jobs.py +7 -3
- nautobot/extras/plugins/views.py +24 -1
- nautobot/extras/secrets/__init__.py +1 -1
- nautobot/extras/tables.py +21 -0
- nautobot/extras/templates/extras/customfield.html +2 -129
- nautobot/extras/templates/extras/customfield_edit.html +2 -108
- nautobot/extras/templates/extras/customfield_retrieve.html +129 -0
- nautobot/extras/templates/extras/customfield_update.html +108 -0
- nautobot/extras/templates/extras/inc/jobresult.html +7 -3
- nautobot/extras/templates/extras/jobresult.html +2 -155
- nautobot/extras/templates/extras/jobresult_retrieve.html +155 -0
- nautobot/extras/templates/extras/marketplace.html +5 -6
- nautobot/extras/templates/extras/note.html +2 -53
- nautobot/extras/templates/extras/note_retrieve.html +53 -0
- nautobot/extras/templates/extras/plugins_list.html +5 -6
- nautobot/extras/templates/extras/secretsgroup_retrieve.html +2 -29
- nautobot/extras/templatetags/custom_links.py +2 -2
- nautobot/extras/templatetags/job_buttons.py +1 -1
- nautobot/extras/templatetags/plugins.py +1 -1
- nautobot/extras/tests/integration/test_computedfields.py +2 -2
- nautobot/extras/tests/integration/test_customfields.py +14 -11
- nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/integration/test_notes.py +1 -1
- nautobot/extras/tests/integration/test_plugins.py +6 -6
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_filters.py +9 -0
- nautobot/extras/tests/test_forms.py +2 -2
- nautobot/extras/tests/test_plugins.py +14 -3
- nautobot/extras/tests/test_relationships.py +7 -7
- nautobot/extras/tests/test_views.py +172 -1
- nautobot/extras/urls.py +3 -59
- nautobot/extras/utils.py +1 -1
- nautobot/extras/views.py +96 -182
- nautobot/ipam/tables.py +8 -15
- nautobot/ipam/tests/migration/test_migrations.py +8 -8
- nautobot/ipam/tests/test_api.py +2 -2
- nautobot/ipam/tests/test_models.py +1 -1
- nautobot/project-static/docs/404.html +23 -0
- nautobot/project-static/docs/apps/index.html +23 -0
- nautobot/project-static/docs/apps/nautobot-apps.html +23 -0
- nautobot/project-static/docs/assets/_mkdocstrings.css +44 -6
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +28 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +25 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +128 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +37 -4
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +39 -6
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +25 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +24 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +32 -5
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +41 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +39 -7
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +43 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +74 -59
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +143 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +43 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +135 -53
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +229 -36
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +27 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +30 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +162 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +258 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5987 -2620
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +25 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +154 -55
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +150 -35
- nautobot/project-static/docs/development/apps/api/configuration-view.html +23 -0
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +23 -0
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +23 -0
- nautobot/project-static/docs/development/apps/api/models/global-search.html +23 -0
- nautobot/project-static/docs/development/apps/api/models/graphql.html +23 -0
- nautobot/project-static/docs/development/apps/api/models/index.html +23 -0
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +23 -0
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +23 -0
- nautobot/project-static/docs/development/apps/api/prometheus.html +23 -0
- nautobot/project-static/docs/development/apps/api/setup.html +23 -0
- nautobot/project-static/docs/development/apps/api/testing.html +23 -0
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +23 -0
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +23 -0
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +23 -0
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +23 -0
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/base-template.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/index.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -2
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/notes.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +23 -0
- nautobot/project-static/docs/development/apps/api/views/urls.html +23 -0
- nautobot/project-static/docs/development/apps/index.html +23 -0
- nautobot/project-static/docs/development/apps/migration/code-updates.html +23 -0
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +23 -0
- nautobot/project-static/docs/development/apps/migration/from-v1.html +23 -0
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +23 -0
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +23 -0
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +23 -0
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +23 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +26 -3
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +10544 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +23 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +23 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +23 -0
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +26 -3
- nautobot/project-static/docs/development/core/application-registry.html +23 -0
- nautobot/project-static/docs/development/core/best-practices.html +23 -0
- nautobot/project-static/docs/development/core/bootstrap-ui.html +23 -0
- nautobot/project-static/docs/development/core/caching.html +23 -0
- nautobot/project-static/docs/development/core/controllers.html +23 -0
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +23 -0
- nautobot/project-static/docs/development/core/generic-views.html +23 -0
- nautobot/project-static/docs/development/core/getting-started.html +23 -0
- nautobot/project-static/docs/development/core/homepage.html +23 -0
- nautobot/project-static/docs/development/core/index.html +23 -0
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +23 -0
- nautobot/project-static/docs/development/core/model-checklist.html +23 -0
- nautobot/project-static/docs/development/core/model-features.html +23 -0
- nautobot/project-static/docs/development/core/natural-keys.html +23 -0
- nautobot/project-static/docs/development/core/navigation-menu.html +23 -0
- nautobot/project-static/docs/development/core/release-checklist.html +23 -0
- nautobot/project-static/docs/development/core/role-internals.html +23 -0
- nautobot/project-static/docs/development/core/settings.html +23 -0
- nautobot/project-static/docs/development/core/style-guide.html +23 -0
- nautobot/project-static/docs/development/core/templates.html +23 -0
- nautobot/project-static/docs/development/core/testing.html +23 -0
- nautobot/project-static/docs/development/core/ui-component-framework.html +713 -255
- nautobot/project-static/docs/development/core/user-preferences.html +23 -0
- nautobot/project-static/docs/development/index.html +23 -0
- nautobot/project-static/docs/development/jobs/getting-started.html +23 -0
- nautobot/project-static/docs/development/jobs/index.html +23 -0
- nautobot/project-static/docs/development/jobs/installation.html +23 -0
- nautobot/project-static/docs/development/jobs/job-extensions.html +23 -0
- nautobot/project-static/docs/development/jobs/job-logging.html +23 -0
- nautobot/project-static/docs/development/jobs/job-patterns.html +23 -0
- nautobot/project-static/docs/development/jobs/job-structure.html +23 -0
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +23 -0
- nautobot/project-static/docs/development/jobs/testing.html +23 -0
- nautobot/project-static/docs/index.html +23 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/breadcrumbs-titles-data-flow.png +0 -0
- nautobot/project-static/docs/media/power_distribution.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +23 -0
- nautobot/project-static/docs/overview/design_philosophy.html +23 -0
- nautobot/project-static/docs/release-notes/index.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.0.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.1.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.2.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.3.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.4.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.5.html +23 -0
- nautobot/project-static/docs/release-notes/version-1.6.html +23 -0
- nautobot/project-static/docs/release-notes/version-2.0.html +23 -0
- nautobot/project-static/docs/release-notes/version-2.1.html +23 -0
- nautobot/project-static/docs/release-notes/version-2.2.html +23 -0
- nautobot/project-static/docs/release-notes/version-2.3.html +23 -0
- nautobot/project-static/docs/release-notes/version-2.4.html +306 -0
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +303 -299
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +23 -0
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +23 -0
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/index.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +23 -0
- nautobot/project-static/docs/user-guide/administration/installation/services.html +23 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +23 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +23 -0
- nautobot/project-static/docs/user-guide/administration/security/index.html +23 -0
- nautobot/project-static/docs/user-guide/administration/security/notices.html +23 -0
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +284 -219
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +23 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +305 -5
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +24 -1
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +136 -3
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +41 -1
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +40 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +23 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +23 -0
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +23 -0
- nautobot/project-static/docs/user-guide/index.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +24 -1
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +23 -0
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +23 -0
- nautobot/users/tests/test_api.py +2 -2
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -252
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -75
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +252 -0
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +75 -0
- nautobot/virtualization/urls.py +3 -61
- nautobot/virtualization/views.py +48 -72
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/METADATA +24 -24
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/RECORD +434 -417
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/NOTICE +0 -0
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/WHEEL +0 -0
- {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/entry_points.txt +0 -0
nautobot/apps/choices.py
CHANGED
|
@@ -18,11 +18,15 @@ from nautobot.dcim.choices import (
|
|
|
18
18
|
InterfaceRedundancyGroupProtocolChoices,
|
|
19
19
|
InterfaceTypeChoices,
|
|
20
20
|
PortTypeChoices,
|
|
21
|
+
PowerFeedBreakerPoleChoices,
|
|
21
22
|
PowerFeedPhaseChoices,
|
|
23
|
+
PowerFeedStatusChoices,
|
|
22
24
|
PowerFeedSupplyChoices,
|
|
23
25
|
PowerFeedTypeChoices,
|
|
24
26
|
PowerOutletFeedLegChoices,
|
|
25
27
|
PowerOutletTypeChoices,
|
|
28
|
+
PowerPanelTypeChoices,
|
|
29
|
+
PowerPathChoices,
|
|
26
30
|
PowerPortTypeChoices,
|
|
27
31
|
RackDimensionUnitChoices,
|
|
28
32
|
RackElevationDetailRenderChoices,
|
|
@@ -89,11 +93,15 @@ __all__ = (
|
|
|
89
93
|
"ObjectChangeActionChoices",
|
|
90
94
|
"ObjectChangeEventContextChoices",
|
|
91
95
|
"PortTypeChoices",
|
|
96
|
+
"PowerFeedBreakerPoleChoices",
|
|
92
97
|
"PowerFeedPhaseChoices",
|
|
98
|
+
"PowerFeedStatusChoices",
|
|
93
99
|
"PowerFeedSupplyChoices",
|
|
94
100
|
"PowerFeedTypeChoices",
|
|
95
101
|
"PowerOutletFeedLegChoices",
|
|
96
102
|
"PowerOutletTypeChoices",
|
|
103
|
+
"PowerPanelTypeChoices",
|
|
104
|
+
"PowerPathChoices",
|
|
97
105
|
"PowerPortTypeChoices",
|
|
98
106
|
"PrefixTypeChoices",
|
|
99
107
|
"RackDimensionUnitChoices",
|
nautobot/apps/ui.py
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from nautobot.core.choices import ButtonColorChoices
|
|
4
4
|
from nautobot.core.ui.base import PermissionsMixin
|
|
5
|
+
from nautobot.core.ui.breadcrumbs import (
|
|
6
|
+
BaseBreadcrumbItem,
|
|
7
|
+
Breadcrumbs,
|
|
8
|
+
InstanceBreadcrumbItem,
|
|
9
|
+
ModelBreadcrumbItem,
|
|
10
|
+
ViewNameBreadcrumbItem,
|
|
11
|
+
)
|
|
5
12
|
from nautobot.core.ui.choices import LayoutChoices, SectionChoices
|
|
6
13
|
from nautobot.core.ui.homepage import (
|
|
7
14
|
HomePageBase,
|
|
@@ -36,6 +43,7 @@ from nautobot.core.ui.object_detail import (
|
|
|
36
43
|
Tab,
|
|
37
44
|
TextPanel,
|
|
38
45
|
)
|
|
46
|
+
from nautobot.core.ui.titles import Titles
|
|
39
47
|
from nautobot.core.ui.utils import render_component_template
|
|
40
48
|
from nautobot.extras.choices import BannerClassChoices
|
|
41
49
|
from nautobot.extras.plugins import Banner, TemplateExtension
|
|
@@ -43,7 +51,9 @@ from nautobot.extras.plugins import Banner, TemplateExtension
|
|
|
43
51
|
__all__ = (
|
|
44
52
|
"Banner",
|
|
45
53
|
"BannerClassChoices",
|
|
54
|
+
"BaseBreadcrumbItem",
|
|
46
55
|
"BaseTextPanel",
|
|
56
|
+
"Breadcrumbs",
|
|
47
57
|
"Button",
|
|
48
58
|
"ButtonColorChoices",
|
|
49
59
|
"Component",
|
|
@@ -55,8 +65,10 @@ __all__ = (
|
|
|
55
65
|
"HomePageGroup",
|
|
56
66
|
"HomePageItem",
|
|
57
67
|
"HomePagePanel",
|
|
68
|
+
"InstanceBreadcrumbItem",
|
|
58
69
|
"KeyValueTablePanel",
|
|
59
70
|
"LayoutChoices",
|
|
71
|
+
"ModelBreadcrumbItem",
|
|
60
72
|
"NavMenuAddButton",
|
|
61
73
|
"NavMenuBase",
|
|
62
74
|
"NavMenuButton",
|
|
@@ -75,5 +87,7 @@ __all__ = (
|
|
|
75
87
|
"Tab",
|
|
76
88
|
"TemplateExtension",
|
|
77
89
|
"TextPanel",
|
|
90
|
+
"Titles",
|
|
91
|
+
"ViewNameBreadcrumbItem",
|
|
78
92
|
"render_component_template",
|
|
79
93
|
)
|
nautobot/core/api/views.py
CHANGED
|
@@ -519,6 +519,8 @@ class StatusView(NautobotAPIVersionMixin, APIView):
|
|
|
519
519
|
if version:
|
|
520
520
|
if isinstance(version, tuple):
|
|
521
521
|
version = ".".join(str(n) for n in version)
|
|
522
|
+
else:
|
|
523
|
+
version = str(version)
|
|
522
524
|
installed_apps[app_config.name] = version
|
|
523
525
|
installed_apps = dict(sorted(installed_apps.items()))
|
|
524
526
|
|
nautobot/core/choices.py
CHANGED
|
@@ -194,6 +194,7 @@ class ButtonActionColorChoices(ChoiceSet):
|
|
|
194
194
|
EXPORT = "success"
|
|
195
195
|
IMPORT = "primary"
|
|
196
196
|
INFO = "info"
|
|
197
|
+
RENAME = "warning"
|
|
197
198
|
SUBMIT = "primary"
|
|
198
199
|
SWAP = "primary"
|
|
199
200
|
|
|
@@ -210,6 +211,7 @@ class ButtonActionColorChoices(ChoiceSet):
|
|
|
210
211
|
(EXPORT, "Export"),
|
|
211
212
|
(IMPORT, "Import"),
|
|
212
213
|
(INFO, "Info"),
|
|
214
|
+
(RENAME, "Rename"),
|
|
213
215
|
(SUBMIT, "Submit"),
|
|
214
216
|
(SWAP, "Swap"),
|
|
215
217
|
)
|
|
@@ -236,6 +238,7 @@ class ButtonActionIconChoices(ChoiceSet):
|
|
|
236
238
|
LOCK = "mdi-lock"
|
|
237
239
|
MAGNIFY = "mdi-magnify"
|
|
238
240
|
NOTE = "mdi-note-text"
|
|
241
|
+
RENAME = "mdi-pencil"
|
|
239
242
|
SWAP = "mdi-swap-vertical"
|
|
240
243
|
TRASH = "mdi-trash-can-outline"
|
|
241
244
|
|
|
@@ -256,6 +259,7 @@ class ButtonActionIconChoices(ChoiceSet):
|
|
|
256
259
|
(LOCK, "Lock"),
|
|
257
260
|
(MAGNIFY, "Magnify"),
|
|
258
261
|
(NOTE, "Note"),
|
|
262
|
+
(RENAME, "Rename"),
|
|
259
263
|
(SWAP, "Swap"),
|
|
260
264
|
(TRASH, "Trash"),
|
|
261
265
|
)
|
nautobot/core/filters.py
CHANGED
|
@@ -209,14 +209,12 @@ class ContentTypeFilterMixin:
|
|
|
209
209
|
return qs
|
|
210
210
|
|
|
211
211
|
if value.isdigit():
|
|
212
|
-
return
|
|
213
|
-
|
|
212
|
+
return self.get_method(qs)(**{f"{self.field_name}__pk": value})
|
|
214
213
|
try:
|
|
215
214
|
app_label, model = value.lower().split(".")
|
|
216
215
|
except ValueError:
|
|
217
216
|
return qs.none()
|
|
218
|
-
|
|
219
|
-
return qs.filter(
|
|
217
|
+
return self.get_method(qs)(
|
|
220
218
|
**{
|
|
221
219
|
f"{self.field_name}__app_label": app_label,
|
|
222
220
|
f"{self.field_name}__model": model,
|
|
@@ -244,6 +242,8 @@ class ContentTypeChoiceFilter(ContentTypeFilterMixin, django_filters.ChoiceFilte
|
|
|
244
242
|
content_type = ContentTypeChoiceFilter(
|
|
245
243
|
choices=FeatureQuery("dynamic_groups").get_choices,
|
|
246
244
|
)
|
|
245
|
+
|
|
246
|
+
In most cases you should use `ContentTypeMultipleChoiceFilter` instead.
|
|
247
247
|
"""
|
|
248
248
|
|
|
249
249
|
|
|
@@ -251,6 +251,9 @@ class ContentTypeMultipleChoiceFilter(django_filters.MultipleChoiceFilter):
|
|
|
251
251
|
"""
|
|
252
252
|
Allows multiple-choice ContentType filtering by <app_label>.<model> (e.g. "dcim.location").
|
|
253
253
|
|
|
254
|
+
Does NOT allow filtering by PK at this time; it would need to be reimplemented similar to
|
|
255
|
+
NaturalKeyOrPKMultipleChoiceFilter as a breaking change.
|
|
256
|
+
|
|
254
257
|
Defaults to joining multiple options with "AND". Pass `conjoined=False` to
|
|
255
258
|
override this behavior to join with "OR" instead.
|
|
256
259
|
|
|
@@ -265,43 +268,14 @@ class ContentTypeMultipleChoiceFilter(django_filters.MultipleChoiceFilter):
|
|
|
265
268
|
kwargs.setdefault("conjoined", True)
|
|
266
269
|
super().__init__(*args, **kwargs)
|
|
267
270
|
|
|
268
|
-
def
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
for v in value:
|
|
277
|
-
if self.conjoined:
|
|
278
|
-
qs = ContentTypeFilter.filter(self, qs, v)
|
|
279
|
-
else:
|
|
280
|
-
if v.isdigit():
|
|
281
|
-
q |= models.Q(**{f"{self.field_name}__pk": value})
|
|
282
|
-
continue
|
|
283
|
-
# Similar to the ContentTypeFilter.filter() call above, but instead of narrowing the query each time
|
|
284
|
-
# (a AND b AND c ...) we broaden the query each time (a OR b OR c ...).
|
|
285
|
-
# Specifically, we're mapping a value like ['dcim.device', 'ipam.vlan'] to a query like
|
|
286
|
-
# Q((field__app_label="dcim" AND field__model="device") OR (field__app_label="ipam" AND field__model="VLAN"))
|
|
287
|
-
try:
|
|
288
|
-
app_label, model = v.lower().split(".")
|
|
289
|
-
except ValueError:
|
|
290
|
-
continue
|
|
291
|
-
q |= models.Q(
|
|
292
|
-
**{
|
|
293
|
-
f"{self.field_name}__app_label": app_label,
|
|
294
|
-
f"{self.field_name}__model": model,
|
|
295
|
-
}
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
if not self.conjoined:
|
|
299
|
-
qs = qs.filter(q)
|
|
300
|
-
|
|
301
|
-
if self.distinct:
|
|
302
|
-
qs = qs.distinct()
|
|
303
|
-
|
|
304
|
-
return qs
|
|
271
|
+
def get_filter_predicate(self, v):
|
|
272
|
+
if v.isdigit():
|
|
273
|
+
return {f"{self.field_name}__pk": v}
|
|
274
|
+
try:
|
|
275
|
+
app_label, model = v.lower().split(".")
|
|
276
|
+
except ValueError:
|
|
277
|
+
return {f"{self.field_name}__pk": v}
|
|
278
|
+
return {f"{self.field_name}__app_label": app_label, f"{self.field_name}__model": model}
|
|
305
279
|
|
|
306
280
|
|
|
307
281
|
class MappedPredicatesFilterMixin:
|
|
@@ -642,6 +616,9 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
642
616
|
(
|
|
643
617
|
django_filters.ModelChoiceFilter,
|
|
644
618
|
django_filters.ModelMultipleChoiceFilter,
|
|
619
|
+
ContentTypeFilter,
|
|
620
|
+
ContentTypeChoiceFilter,
|
|
621
|
+
ContentTypeMultipleChoiceFilter,
|
|
645
622
|
MultiValueUUIDFilter,
|
|
646
623
|
TagFilter,
|
|
647
624
|
TreeNodeMultipleChoiceFilter,
|
|
@@ -820,6 +797,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
820
797
|
to_field_name="name",
|
|
821
798
|
label="Contacts (name or ID)",
|
|
822
799
|
)
|
|
800
|
+
cls.declared_filters["contacts"] = filters["contacts"] # pylint: disable=no-member
|
|
823
801
|
|
|
824
802
|
if "teams" not in filters:
|
|
825
803
|
filters["teams"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
@@ -828,6 +806,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
828
806
|
to_field_name="name",
|
|
829
807
|
label="Teams (name or ID)",
|
|
830
808
|
)
|
|
809
|
+
cls.declared_filters["teams"] = filters["teams"] # pylint: disable=no-member
|
|
831
810
|
|
|
832
811
|
if "dynamic_groups" not in filters and getattr(cls._meta.model, "is_dynamic_group_associable_model", False): # pylint: disable=no-member
|
|
833
812
|
if not hasattr(cls._meta.model, "static_group_association_set"): # pylint: disable=no-member
|
|
@@ -848,6 +827,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
848
827
|
query_params={"content_type": cls._meta.model._meta.label_lower}, # pylint: disable=no-member
|
|
849
828
|
label="Dynamic groups (name or ID)",
|
|
850
829
|
)
|
|
830
|
+
cls.declared_filters["dynamic_groups"] = filters["dynamic_groups"] # pylint: disable=no-member
|
|
851
831
|
|
|
852
832
|
# django-filters has no concept of "abstract" filtersets, so we have to fake it
|
|
853
833
|
if cls._meta.model is not None: # pylint: disable=no-member
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from django.core.exceptions import ValidationError
|
|
2
|
+
from django.core.management.base import BaseCommand
|
|
3
|
+
|
|
4
|
+
from nautobot.extras.models import Job, ScheduledJob
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ApprovalRequiredScheduledJobsError(ValidationError):
|
|
8
|
+
"""Raised when scheduled jobs requiring approval are found during managment command."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, message_lines):
|
|
11
|
+
self.message_lines = message_lines
|
|
12
|
+
super().__init__(message_lines)
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return "\n".join(self.message_lines)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Command(BaseCommand):
|
|
19
|
+
help = "Checks for scheduled jobs and jobs that require approval."
|
|
20
|
+
|
|
21
|
+
def handle(self, *args, **options):
|
|
22
|
+
approval_required_scheduled_jobs = ScheduledJob.objects.filter(approval_required=True).values_list("id", "name")
|
|
23
|
+
|
|
24
|
+
if approval_required_scheduled_jobs:
|
|
25
|
+
message_lines = [
|
|
26
|
+
"These need to be approved (and run) or denied before upgrading to Nautobot v3, as the introduction of the approval workflows feature means that future scheduled-job approvals will be handled differently.",
|
|
27
|
+
"Refer to the documentation: https://docs.nautobot.com/projects/core/en/v2.4.14/user-guide/platform-functionality/jobs/job-scheduling-and-approvals/#approval-via-the-ui",
|
|
28
|
+
"Below is a list of affected scheduled jobs:",
|
|
29
|
+
]
|
|
30
|
+
for schedule_job_id, scheduled_job_name in approval_required_scheduled_jobs:
|
|
31
|
+
message_lines.append(f" - ID: {schedule_job_id}, Name: {scheduled_job_name}")
|
|
32
|
+
raise ApprovalRequiredScheduledJobsError(message_lines)
|
|
33
|
+
|
|
34
|
+
approval_required_jobs = Job.objects.filter(approval_required=True).values_list("name", flat=True)
|
|
35
|
+
if approval_required_jobs:
|
|
36
|
+
message_lines = [
|
|
37
|
+
"Following jobs still have `approval_required=True`.",
|
|
38
|
+
"These jobs will no longer trigger approval automatically.",
|
|
39
|
+
"After upgrading to Nautobot 3.x, you should add an approval workflow definition(s) covering these jobs.",
|
|
40
|
+
"Refer to the documentation: https://docs.nautobot.com/projects/core/en/v3.0.0/user-guide/platform-functionality/approval-workflow/",
|
|
41
|
+
"Affected jobs (Names):",
|
|
42
|
+
]
|
|
43
|
+
for job_name in approval_required_jobs:
|
|
44
|
+
message_lines.append(f" - {job_name}")
|
|
45
|
+
else:
|
|
46
|
+
message_lines = ["No approval_required jobs or scheduled jobs found."]
|
|
47
|
+
self.stdout.write("\n".join(message_lines))
|
|
@@ -375,7 +375,7 @@ class Command(BaseCommand):
|
|
|
375
375
|
confirm = input(
|
|
376
376
|
f"""\
|
|
377
377
|
You have requested a flush of the database before generating new data.
|
|
378
|
-
This will IRREVERSIBLY DESTROY all data in the "{connections[options[
|
|
378
|
+
This will IRREVERSIBLY DESTROY all data in the "{connections[options["database"]].settings_dict["NAME"]}" database,
|
|
379
379
|
including all user accounts, and return each table to an empty state.
|
|
380
380
|
Are you SURE you want to do this?
|
|
381
381
|
|
|
@@ -92,6 +92,6 @@ class Command(_Command):
|
|
|
92
92
|
|
|
93
93
|
for key, value in self.affected_models_count.items():
|
|
94
94
|
if value:
|
|
95
|
-
self.stdout.write(f" Affected {key:<38} {value: 8} rows {elapsed/value:6.3f}s/record")
|
|
95
|
+
self.stdout.write(f" Affected {key:<38} {value: 8} rows {elapsed / value:6.3f}s/record")
|
|
96
96
|
else:
|
|
97
97
|
self.stdout.write(f" Affected {key:<38} {value: 8} rows")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from django.core.cache import cache
|
|
2
2
|
from django.db.models import Case, When
|
|
3
3
|
from django.db.models.signals import post_delete, post_save
|
|
4
|
+
from tree_queries.compiler import TreeQuery
|
|
4
5
|
from tree_queries.models import TreeNode
|
|
5
6
|
from tree_queries.query import TreeManager as TreeManager_, TreeQuerySet as TreeQuerySet_
|
|
6
7
|
|
|
@@ -61,6 +62,22 @@ class TreeQuerySet(TreeQuerySet_, querysets.RestrictedQuerySet):
|
|
|
61
62
|
return deepest.tree_depth
|
|
62
63
|
return 0
|
|
63
64
|
|
|
65
|
+
def count(self):
|
|
66
|
+
"""Custom count method for optimization purposes.
|
|
67
|
+
|
|
68
|
+
TreeQuerySet instances in Nautobot are by default with tree fields. So if somewhere tree fields aren't
|
|
69
|
+
explicitly removed from the queryset and count is called, the whole tree is calculated. Since this is not
|
|
70
|
+
needed, this implementation calls `without_tree_fields` before issuing the count query and `with_tree_fields`
|
|
71
|
+
afterwards when applicable.
|
|
72
|
+
"""
|
|
73
|
+
should_have_tree_fields = isinstance(self.query, TreeQuery)
|
|
74
|
+
if should_have_tree_fields:
|
|
75
|
+
self.without_tree_fields()
|
|
76
|
+
count = super().count()
|
|
77
|
+
if should_have_tree_fields:
|
|
78
|
+
self.with_tree_fields()
|
|
79
|
+
return count
|
|
80
|
+
|
|
64
81
|
|
|
65
82
|
class TreeManager(TreeManager_, BaseManager.from_queryset(TreeQuerySet)):
|
|
66
83
|
"""
|
nautobot/core/settings.py
CHANGED
|
@@ -765,7 +765,7 @@ CONSTANCE_CONFIG = {
|
|
|
765
765
|
),
|
|
766
766
|
"JOB_CREATE_FILE_MAX_SIZE": ConstanceConfigItem(
|
|
767
767
|
default=10 << 20,
|
|
768
|
-
help_text=mark_safe(
|
|
768
|
+
help_text=mark_safe(
|
|
769
769
|
"Maximum size (in bytes) of any single file generated by a <code>Job.create_file()</code> call."
|
|
770
770
|
),
|
|
771
771
|
field_type=int,
|
|
@@ -798,7 +798,7 @@ CONSTANCE_CONFIG = {
|
|
|
798
798
|
),
|
|
799
799
|
"NETWORK_DRIVERS": ConstanceConfigItem(
|
|
800
800
|
default={},
|
|
801
|
-
help_text=mark_safe(
|
|
801
|
+
help_text=mark_safe(
|
|
802
802
|
"Extend or override default Platform.network_driver translations provided by "
|
|
803
803
|
'<a href="https://netutils.readthedocs.io/en/latest/user/lib_use_cases_lib_mapper/">netutils</a>. '
|
|
804
804
|
"Enter a dictionary in JSON format, for example:\n"
|
nautobot/core/tables.py
CHANGED
|
@@ -5,7 +5,7 @@ from django.conf import settings
|
|
|
5
5
|
from django.contrib.auth.models import AnonymousUser
|
|
6
6
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
7
7
|
from django.core.exceptions import FieldDoesNotExist, FieldError
|
|
8
|
-
from django.db.models import Prefetch
|
|
8
|
+
from django.db.models import Prefetch, QuerySet
|
|
9
9
|
from django.db.models.fields.related import ForeignKey, RelatedField
|
|
10
10
|
from django.db.models.fields.reverse_related import ManyToOneRel
|
|
11
11
|
from django.urls import reverse
|
|
@@ -333,6 +333,29 @@ class BaseTable(django_tables2.Table):
|
|
|
333
333
|
# Otherwise, use the default sorting method
|
|
334
334
|
self.data.order_by(self._order_by)
|
|
335
335
|
|
|
336
|
+
def add_conditional_prefetch(self, table_field, db_column=None, prefetch=None):
|
|
337
|
+
"""Conditionally prefetch the specified database column if the related table field is visible.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
table_field (str): Name of the field on the table to check for visibility. Also used as the prefetch field
|
|
341
|
+
if neither db_column nor prefetch is specified.
|
|
342
|
+
db_column (str): Optionally specify the db column to prefetch. Mutually exclusive with prefetch.
|
|
343
|
+
prefetch (Prefetch): Optionally specify a prefetch object. Mutually exclusive with db_column.
|
|
344
|
+
"""
|
|
345
|
+
if db_column and prefetch:
|
|
346
|
+
raise ValueError(
|
|
347
|
+
"BaseTable.add_conditional_prefetch called with both db_column and prefetch, this is not allowed."
|
|
348
|
+
)
|
|
349
|
+
if not db_column:
|
|
350
|
+
db_column = table_field
|
|
351
|
+
if table_field in self.columns and self.columns[table_field].visible and isinstance(self.data.data, QuerySet):
|
|
352
|
+
if prefetch:
|
|
353
|
+
self.data = TableData.from_data(self.data.data.prefetch_related(prefetch))
|
|
354
|
+
else:
|
|
355
|
+
self.data = TableData.from_data(self.data.data.prefetch_related(db_column))
|
|
356
|
+
self.data.set_table(self)
|
|
357
|
+
self.rows = BoundRows(data=self.data, table=self, pinned_data=self.pinned_data)
|
|
358
|
+
|
|
336
359
|
|
|
337
360
|
#
|
|
338
361
|
# Table columns
|
|
@@ -353,7 +376,7 @@ class ToggleColumn(django_tables2.CheckBoxColumn):
|
|
|
353
376
|
|
|
354
377
|
@property
|
|
355
378
|
def header(self):
|
|
356
|
-
return mark_safe('<input type="checkbox" class="toggle" title="Toggle all" />')
|
|
379
|
+
return mark_safe('<input type="checkbox" class="toggle" title="Toggle all" />')
|
|
357
380
|
|
|
358
381
|
|
|
359
382
|
class BooleanColumn(django_tables2.Column):
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<!DOCTYPE html>
|
|
6
6
|
<html lang="en"{% if request.COOKIES|get_item:"theme" == 'dark' %} data-theme="dark"{% endif %}>
|
|
7
7
|
<head>
|
|
8
|
-
<title>{% block title %}Home{% endblock %} - {{ settings.BRANDING_TITLE }}</title>
|
|
8
|
+
<title>{% block title %}Home{% endblock %}{% block document_title_extra %}{% endblock %} - {{ settings.BRANDING_TITLE }}</title>
|
|
9
9
|
{% include 'inc/media.html' %}
|
|
10
10
|
{% block extra_styles %}{% endblock %}
|
|
11
11
|
</head>
|
|
@@ -4,18 +4,26 @@
|
|
|
4
4
|
{% load perms %}
|
|
5
5
|
{% load plugins %}
|
|
6
6
|
{% load static %}
|
|
7
|
+
{% load ui_framework %}
|
|
8
|
+
|
|
9
|
+
{% block document_title_extra %}{% saved_view_title "plain" %}{% endblock %}
|
|
7
10
|
|
|
8
11
|
{% block header %}
|
|
9
12
|
<div class="row noprint">
|
|
10
13
|
<div class="{% if search_form %}col-sm-8 col-md-9 {% else %} col-md-12 {% endif %}">
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
{% if breadcrumbs is not None %}
|
|
15
|
+
{% render_breadcrumbs %}
|
|
16
|
+
{% else %}
|
|
17
|
+
{# TODO: remove this fragment after breadcrumbs implementation in generic views like ConsoleConnectionsListView #}
|
|
18
|
+
<ol class="breadcrumb">
|
|
19
|
+
{% block breadcrumbs %}
|
|
20
|
+
{% if list_url %}
|
|
21
|
+
<li><a href="{% url list_url %}">{{ title }}</a></li>
|
|
22
|
+
{% endif %}
|
|
23
|
+
{% block extra_breadcrumbs %}{% endblock extra_breadcrumbs %}
|
|
24
|
+
{% endblock breadcrumbs %}
|
|
25
|
+
</ol>
|
|
26
|
+
{% endif %}
|
|
19
27
|
</div>
|
|
20
28
|
{% if search_form %}
|
|
21
29
|
<div class="col-sm-4 col-md-3">
|
|
@@ -146,18 +154,7 @@
|
|
|
146
154
|
{% endblock export_button %}
|
|
147
155
|
{% endif %}
|
|
148
156
|
</div>
|
|
149
|
-
<h1>{% block title %}
|
|
150
|
-
{{ title }}
|
|
151
|
-
{% if current_saved_view %}
|
|
152
|
-
—
|
|
153
|
-
{% if new_changes_not_applied %}
|
|
154
|
-
<i title="Pending changes not saved">{{ current_saved_view.name }}</i>
|
|
155
|
-
{% else %}
|
|
156
|
-
{{ current_saved_view.name }}
|
|
157
|
-
{% endif %}
|
|
158
|
-
{% endif %}
|
|
159
|
-
{% endblock %}
|
|
160
|
-
</h1>
|
|
157
|
+
<h1>{% block title %}{% render_title %}{% endblock %}{% saved_view_title %}</h1>
|
|
161
158
|
{% block header_extra %}{% endblock %}
|
|
162
159
|
{% if filter_params %}
|
|
163
160
|
<div class="filters-applied">
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<ol class="breadcrumb">
|
|
2
|
+
{% block breadcrumbs %}
|
|
3
|
+
{% for url, title in breadcrumbs_items %}
|
|
4
|
+
<li>
|
|
5
|
+
{% if url %}
|
|
6
|
+
<a href="{{ url }}">{{ title }}</a>
|
|
7
|
+
{% else %}
|
|
8
|
+
{{ title }}
|
|
9
|
+
{% endif %}
|
|
10
|
+
</li>
|
|
11
|
+
{% endfor %}
|
|
12
|
+
{% block extra_breadcrumbs %}{% endblock extra_breadcrumbs %}
|
|
13
|
+
{% endblock %}
|
|
14
|
+
</ol>
|
|
@@ -176,8 +176,6 @@ def consolidate_bulk_action_buttons(context):
|
|
|
176
176
|
"bulk_action_buttons": bulk_action_buttons,
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
params = ("?" + context["request"].GET.urlencode()) if context["request"].GET else ""
|
|
180
|
-
|
|
181
179
|
primary_button_fragment = child_button_fragment = """
|
|
182
180
|
<button {attrs}>
|
|
183
181
|
<span class="{icon}" aria-hidden="true"></span> {label}
|
|
@@ -203,7 +201,7 @@ def consolidate_bulk_action_buttons(context):
|
|
|
203
201
|
attrs=render_tag_attrs(
|
|
204
202
|
{
|
|
205
203
|
"class": edit_button_classes,
|
|
206
|
-
"formaction": reverse(context["bulk_edit_url"])
|
|
204
|
+
"formaction": reverse(context["bulk_edit_url"]),
|
|
207
205
|
"type": "submit",
|
|
208
206
|
}
|
|
209
207
|
),
|
|
@@ -242,7 +240,7 @@ def consolidate_bulk_action_buttons(context):
|
|
|
242
240
|
"class": delete_button_classes,
|
|
243
241
|
"type": "submit",
|
|
244
242
|
"name": "_delete",
|
|
245
|
-
"formaction": reverse(context["bulk_delete_url"])
|
|
243
|
+
"formaction": reverse(context["bulk_delete_url"]),
|
|
246
244
|
}
|
|
247
245
|
),
|
|
248
246
|
icon="mdi mdi-trash-can-outline",
|
|
@@ -2,6 +2,7 @@ import datetime
|
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
|
+
from typing import Literal
|
|
5
6
|
from urllib.parse import parse_qs, quote_plus
|
|
6
7
|
|
|
7
8
|
from django import template
|
|
@@ -12,7 +13,7 @@ from django.contrib.staticfiles.finders import find
|
|
|
12
13
|
from django.core.exceptions import ObjectDoesNotExist
|
|
13
14
|
from django.templatetags.static import static, StaticNode
|
|
14
15
|
from django.urls import NoReverseMatch, reverse
|
|
15
|
-
from django.utils.html import format_html, format_html_join
|
|
16
|
+
from django.utils.html import format_html, format_html_join, strip_tags
|
|
16
17
|
from django.utils.safestring import mark_safe
|
|
17
18
|
from django.utils.text import slugify as django_slugify
|
|
18
19
|
from django_jinja import library
|
|
@@ -25,10 +26,9 @@ from nautobot.core.constants import PAGINATE_COUNT_DEFAULT
|
|
|
25
26
|
from nautobot.core.utils import color, config, data, logging as nautobot_logging, lookup
|
|
26
27
|
from nautobot.core.utils.requests import add_nautobot_version_query_param_to_url
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
HTML_NONE = mark_safe('<span class="text-muted">—</span>') # noqa: S308
|
|
29
|
+
HTML_TRUE = mark_safe('<span class="text-success"><i class="mdi mdi-check-bold" title="Yes"></i></span>')
|
|
30
|
+
HTML_FALSE = mark_safe('<span class="text-danger"><i class="mdi mdi-close-thick" title="No"></i></span>')
|
|
31
|
+
HTML_NONE = mark_safe('<span class="text-muted">—</span>')
|
|
32
32
|
|
|
33
33
|
DEFAULT_SUPPORT_MESSAGE = (
|
|
34
34
|
"If further assistance is required, please join the `#nautobot` channel "
|
|
@@ -1124,7 +1124,7 @@ def custom_branding_or_static(branding_asset, static_asset):
|
|
|
1124
1124
|
branding has been configured in settings, else it returns stock branding via static.
|
|
1125
1125
|
"""
|
|
1126
1126
|
if settings.BRANDING_FILEPATHS.get(branding_asset):
|
|
1127
|
-
url = f"{
|
|
1127
|
+
url = f"{settings.MEDIA_URL}{settings.BRANDING_FILEPATHS.get(branding_asset)}"
|
|
1128
1128
|
else:
|
|
1129
1129
|
url = StaticNode.handle_simple(static_asset)
|
|
1130
1130
|
return add_nautobot_version_query_param_to_url(url)
|
|
@@ -1255,3 +1255,26 @@ def _build_hyperlink(value, field="", target="", rel=""):
|
|
|
1255
1255
|
except AttributeError:
|
|
1256
1256
|
pass
|
|
1257
1257
|
return format_html("{}", display)
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
@register.simple_tag(takes_context=True)
|
|
1261
|
+
def saved_view_title(context, mode: Literal["html", "plain"] = "html"):
|
|
1262
|
+
"""
|
|
1263
|
+
Creates a formatted title that includes saved view information.
|
|
1264
|
+
Usage: <h1>{{ title }}{% saved_view_title "html" %}</h1>
|
|
1265
|
+
"""
|
|
1266
|
+
new_changes_not_applied = context.get("new_changes_not_applied", False)
|
|
1267
|
+
current_saved_view = context.get("current_saved_view")
|
|
1268
|
+
|
|
1269
|
+
if not current_saved_view:
|
|
1270
|
+
return ""
|
|
1271
|
+
|
|
1272
|
+
if new_changes_not_applied:
|
|
1273
|
+
title = format_html(' — <i title="Pending changes not saved">{}</i>', current_saved_view.name)
|
|
1274
|
+
else:
|
|
1275
|
+
title = format_html(" — {}", current_saved_view.name)
|
|
1276
|
+
|
|
1277
|
+
if mode == "plain":
|
|
1278
|
+
return strip_tags(title)
|
|
1279
|
+
|
|
1280
|
+
return title
|
|
@@ -3,6 +3,8 @@ import logging
|
|
|
3
3
|
from django import template
|
|
4
4
|
from django.utils.html import format_html_join
|
|
5
5
|
|
|
6
|
+
from nautobot.core.ui.breadcrumbs import Breadcrumbs
|
|
7
|
+
from nautobot.core.ui.titles import Titles
|
|
6
8
|
from nautobot.core.utils.lookup import get_view_for_model
|
|
7
9
|
from nautobot.core.views.utils import get_obj_from_context
|
|
8
10
|
|
|
@@ -27,6 +29,25 @@ def render_components(context, components):
|
|
|
27
29
|
return ""
|
|
28
30
|
|
|
29
31
|
|
|
32
|
+
@register.simple_tag(takes_context=True)
|
|
33
|
+
def render_title(context, mode="plain"):
|
|
34
|
+
title_obj = context.get("view_titles")
|
|
35
|
+
if title_obj is not None and isinstance(title_obj, Titles):
|
|
36
|
+
return title_obj.render(context, mode=mode)
|
|
37
|
+
|
|
38
|
+
if fallback_title := context.get("title"):
|
|
39
|
+
return fallback_title
|
|
40
|
+
return ""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@register.simple_tag(takes_context=True)
|
|
44
|
+
def render_breadcrumbs(context):
|
|
45
|
+
breadcrumbs_obj = context.get("breadcrumbs")
|
|
46
|
+
if breadcrumbs_obj is not None and isinstance(breadcrumbs_obj, Breadcrumbs):
|
|
47
|
+
return breadcrumbs_obj.render(context)
|
|
48
|
+
return ""
|
|
49
|
+
|
|
50
|
+
|
|
30
51
|
@register.simple_tag(takes_context=True)
|
|
31
52
|
def render_detail_view_extra_buttons(context):
|
|
32
53
|
"""
|