nautobot 2.4.10__py3-none-any.whl → 2.4.11__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/cloud/tests/test_views.py +13 -1
- nautobot/cloud/views.py +39 -9
- nautobot/core/celery/__init__.py +21 -0
- nautobot/core/celery/encoders.py +3 -0
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/jobs/bulk_actions.py +8 -8
- nautobot/core/jobs/cleanup.py +11 -0
- nautobot/core/management/commands/generate_test_data.py +2 -1
- nautobot/core/templates/generic/object_retrieve.html +1 -1
- nautobot/core/testing/mixins.py +19 -1
- nautobot/core/testing/views.py +104 -8
- nautobot/core/tests/test_jobs.py +20 -4
- nautobot/core/tests/test_utils.py +193 -0
- nautobot/core/tests/test_views_utils.py +53 -2
- nautobot/core/ui/object_detail.py +4 -0
- nautobot/core/utils/lookup.py +4 -2
- nautobot/core/utils/module_loading.py +86 -58
- nautobot/core/views/generic.py +2 -12
- nautobot/core/views/mixins.py +19 -1
- nautobot/core/views/renderers.py +4 -13
- nautobot/core/views/utils.py +16 -0
- nautobot/dcim/api/serializers.py +13 -0
- nautobot/dcim/api/urls.py +1 -0
- nautobot/dcim/api/views.py +20 -0
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/factory.py +11 -0
- nautobot/dcim/filters/__init__.py +110 -0
- nautobot/dcim/forms.py +205 -19
- nautobot/dcim/migrations/0070_modulefamily_models.py +92 -0
- nautobot/dcim/models/__init__.py +2 -0
- nautobot/dcim/models/device_component_templates.py +14 -0
- nautobot/dcim/models/device_components.py +13 -1
- nautobot/dcim/models/devices.py +62 -0
- nautobot/dcim/navigation.py +16 -0
- nautobot/dcim/tables/__init__.py +2 -0
- nautobot/dcim/tables/devices.py +48 -0
- nautobot/dcim/tables/devicetypes.py +35 -1
- nautobot/dcim/tables/template_code.py +2 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +1 -90
- nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
- nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +1 -63
- nautobot/dcim/templates/dcim/location.html +2 -249
- nautobot/dcim/templates/dcim/location_edit.html +2 -38
- nautobot/dcim/templates/dcim/location_retrieve.html +249 -0
- nautobot/dcim/templates/dcim/location_update.html +38 -0
- nautobot/dcim/templates/dcim/module_update.html +1 -0
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +93 -1
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +31 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +6 -0
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -160
- nautobot/dcim/tests/test_api.py +35 -0
- nautobot/dcim/tests/test_filters.py +102 -3
- nautobot/dcim/tests/test_models.py +146 -0
- nautobot/dcim/tests/test_views.py +70 -97
- nautobot/dcim/urls.py +4 -22
- nautobot/dcim/views.py +439 -153
- nautobot/extras/api/views.py +9 -2
- nautobot/extras/datasources/git.py +11 -3
- nautobot/extras/forms/forms.py +9 -5
- nautobot/extras/jobs.py +4 -2
- nautobot/extras/models/datasources.py +5 -8
- nautobot/extras/models/jobs.py +5 -0
- nautobot/extras/plugins/__init__.py +3 -0
- nautobot/extras/tables.py +40 -3
- nautobot/extras/templates/extras/configcontext.html +2 -220
- nautobot/extras/templates/extras/configcontext_edit.html +2 -50
- nautobot/extras/templates/extras/configcontext_retrieve.html +2 -0
- nautobot/extras/templates/extras/configcontext_update.html +50 -0
- nautobot/extras/templates/extras/configcontextschema.html +2 -48
- nautobot/extras/templates/extras/configcontextschema_edit.html +2 -19
- nautobot/extras/templates/extras/configcontextschema_retrieve.html +48 -0
- nautobot/extras/templates/extras/configcontextschema_update.html +19 -0
- nautobot/extras/templates/extras/inc/configcontext_data.html +1 -0
- nautobot/extras/templates/extras/inc/json_data.html +1 -1
- nautobot/extras/templates/extras/inc/json_format.html +2 -2
- nautobot/extras/templates/extras/job_edit.html +12 -6
- nautobot/extras/templates/extras/tag.html +2 -52
- nautobot/extras/templates/extras/tag_edit.html +2 -15
- nautobot/extras/templates/extras/tag_retrieve.html +52 -0
- nautobot/extras/templates/extras/tag_update.html +15 -0
- nautobot/extras/templates/extras/team_retrieve.html +2 -2
- nautobot/extras/tests/test_api.py +15 -15
- nautobot/extras/tests/test_filters.py +4 -4
- nautobot/extras/tests/test_jobs.py +23 -10
- nautobot/extras/tests/test_models.py +19 -8
- nautobot/extras/tests/test_plugins.py +6 -3
- nautobot/extras/tests/test_views.py +66 -11
- nautobot/extras/urls.py +4 -134
- nautobot/extras/views.py +113 -158
- nautobot/ipam/models.py +19 -4
- nautobot/ipam/tables.py +19 -0
- nautobot/ipam/templates/ipam/vlan.html +2 -84
- nautobot/ipam/templates/ipam/vlan_edit.html +2 -24
- nautobot/ipam/templates/ipam/vlan_retrieve.html +84 -0
- nautobot/ipam/templates/ipam/vlan_update.html +24 -0
- nautobot/ipam/tests/test_views.py +5 -0
- nautobot/ipam/urls.py +1 -21
- nautobot/ipam/views.py +45 -70
- nautobot/project-static/docs/404.html +31 -8
- nautobot/project-static/docs/apps/index.html +31 -8
- nautobot/project-static/docs/apps/nautobot-apps.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +120 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +31 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +31 -8
- nautobot/project-static/docs/development/apps/api/configuration-view.html +31 -8
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +31 -8
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +31 -8
- nautobot/project-static/docs/development/apps/api/models/global-search.html +31 -8
- nautobot/project-static/docs/development/apps/api/models/graphql.html +31 -8
- nautobot/project-static/docs/development/apps/api/models/index.html +31 -8
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +40 -8
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +32 -9
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +31 -8
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +31 -8
- nautobot/project-static/docs/development/apps/api/prometheus.html +31 -8
- nautobot/project-static/docs/development/apps/api/setup.html +31 -8
- nautobot/project-static/docs/development/apps/api/testing.html +31 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +31 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +31 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +31 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +31 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/base-template.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/index.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/notes.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +31 -8
- nautobot/project-static/docs/development/apps/api/views/urls.html +31 -8
- nautobot/project-static/docs/development/apps/index.html +31 -8
- nautobot/project-static/docs/development/apps/migration/code-updates.html +31 -8
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +31 -8
- nautobot/project-static/docs/development/apps/migration/from-v1.html +31 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +31 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +31 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +31 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +31 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +31 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +31 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +31 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +31 -8
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +31 -8
- nautobot/project-static/docs/development/core/application-registry.html +31 -8
- nautobot/project-static/docs/development/core/best-practices.html +31 -8
- nautobot/project-static/docs/development/core/bootstrap-ui.html +31 -8
- nautobot/project-static/docs/development/core/caching.html +31 -8
- nautobot/project-static/docs/development/core/controllers.html +31 -8
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +31 -8
- nautobot/project-static/docs/development/core/generic-views.html +31 -8
- nautobot/project-static/docs/development/core/getting-started.html +31 -8
- nautobot/project-static/docs/development/core/homepage.html +31 -8
- nautobot/project-static/docs/development/core/index.html +31 -8
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +31 -8
- nautobot/project-static/docs/development/core/model-checklist.html +31 -8
- nautobot/project-static/docs/development/core/model-features.html +31 -8
- nautobot/project-static/docs/development/core/natural-keys.html +31 -8
- nautobot/project-static/docs/development/core/navigation-menu.html +31 -8
- nautobot/project-static/docs/development/core/release-checklist.html +31 -8
- nautobot/project-static/docs/development/core/role-internals.html +31 -8
- nautobot/project-static/docs/development/core/settings.html +31 -8
- nautobot/project-static/docs/development/core/style-guide.html +31 -8
- nautobot/project-static/docs/development/core/templates.html +31 -8
- nautobot/project-static/docs/development/core/testing.html +31 -8
- nautobot/project-static/docs/development/core/ui-component-framework.html +31 -8
- nautobot/project-static/docs/development/core/user-preferences.html +31 -8
- nautobot/project-static/docs/development/index.html +31 -8
- nautobot/project-static/docs/development/jobs/getting-started.html +35 -8
- nautobot/project-static/docs/development/jobs/index.html +31 -8
- nautobot/project-static/docs/development/jobs/installation.html +31 -8
- nautobot/project-static/docs/development/jobs/job-extensions.html +31 -8
- nautobot/project-static/docs/development/jobs/job-logging.html +31 -8
- nautobot/project-static/docs/development/jobs/job-patterns.html +31 -8
- nautobot/project-static/docs/development/jobs/job-structure.html +31 -8
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +31 -8
- nautobot/project-static/docs/development/jobs/testing.html +31 -8
- nautobot/project-static/docs/index.html +31 -8
- nautobot/project-static/docs/insert-analytics.sh +36 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +31 -8
- nautobot/project-static/docs/overview/design_philosophy.html +31 -8
- nautobot/project-static/docs/release-notes/index.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.0.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.1.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.2.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.3.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.4.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.5.html +31 -8
- nautobot/project-static/docs/release-notes/version-1.6.html +31 -8
- nautobot/project-static/docs/release-notes/version-2.0.html +31 -8
- nautobot/project-static/docs/release-notes/version-2.1.html +31 -8
- nautobot/project-static/docs/release-notes/version-2.2.html +31 -8
- nautobot/project-static/docs/release-notes/version-2.3.html +31 -8
- nautobot/project-static/docs/release-notes/version-2.4.html +252 -8
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +302 -298
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +31 -8
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +31 -8
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/index.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +31 -8
- nautobot/project-static/docs/user-guide/administration/installation/services.html +31 -8
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +31 -8
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +31 -8
- nautobot/project-static/docs/user-guide/administration/security/index.html +31 -8
- nautobot/project-static/docs/user-guide/administration/security/notices.html +31 -8
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +31 -8
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +31 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +43 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +35 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +35 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +35 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +10261 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +34 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +31 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +41 -15
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +31 -8
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +31 -8
- nautobot/project-static/docs/user-guide/index.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +37 -9
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +31 -8
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +31 -8
- nautobot/tenancy/tables.py +2 -0
- nautobot/virtualization/tests/test_views.py +1 -1
- nautobot/wireless/forms.py +0 -1
- nautobot/wireless/models.py +1 -1
- nautobot/wireless/tables.py +7 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/METADATA +4 -4
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/RECORD +416 -401
- /nautobot/dcim/templates/dcim/{platform_edit.html → platform_create.html} +0 -0
- /nautobot/extras/test_jobs/{pass.py → pass_job.py} +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/NOTICE +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/WHEEL +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/entry_points.txt +0 -0
nautobot/dcim/views.py
CHANGED
|
@@ -16,6 +16,7 @@ from django.forms import (
|
|
|
16
16
|
MultipleHiddenInput,
|
|
17
17
|
)
|
|
18
18
|
from django.shortcuts import get_object_or_404, HttpResponse, redirect, render
|
|
19
|
+
from django.template.loader import render_to_string
|
|
19
20
|
from django.urls import reverse
|
|
20
21
|
from django.utils.encoding import iri_to_uri
|
|
21
22
|
from django.utils.functional import cached_property
|
|
@@ -71,6 +72,7 @@ from nautobot.wireless.models import (
|
|
|
71
72
|
from nautobot.wireless.tables import (
|
|
72
73
|
ControllerManagedDeviceGroupRadioProfileAssignmentTable,
|
|
73
74
|
ControllerManagedDeviceGroupWirelessNetworkAssignmentTable,
|
|
75
|
+
DeviceGroupWirelessNetworkTable,
|
|
74
76
|
RadioProfileTable,
|
|
75
77
|
)
|
|
76
78
|
|
|
@@ -106,6 +108,7 @@ from .models import (
|
|
|
106
108
|
Module,
|
|
107
109
|
ModuleBay,
|
|
108
110
|
ModuleBayTemplate,
|
|
111
|
+
ModuleFamily,
|
|
109
112
|
ModuleType,
|
|
110
113
|
PathEndpoint,
|
|
111
114
|
Platform,
|
|
@@ -251,21 +254,22 @@ class LocationTypeUIViewSet(NautobotUIViewSet):
|
|
|
251
254
|
#
|
|
252
255
|
|
|
253
256
|
|
|
254
|
-
class
|
|
255
|
-
queryset = Location.objects.all()
|
|
256
|
-
filterset = filters.LocationFilterSet
|
|
257
|
-
filterset_form = forms.LocationFilterForm
|
|
258
|
-
table = tables.LocationTable
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
class LocationView(generic.ObjectView):
|
|
257
|
+
class LocationUIViewSet(NautobotUIViewSet):
|
|
262
258
|
# We aren't accessing tree fields anywhere so this is safe (note that `parent` itself is a normal foreign
|
|
263
259
|
# key, not a tree field). If we ever do access tree fields, this will perform worse, because django will
|
|
264
260
|
# automatically issue a second query (similar to behavior for
|
|
265
261
|
# https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.only)
|
|
266
|
-
queryset = Location.objects.without_tree_fields().
|
|
262
|
+
queryset = Location.objects.without_tree_fields().select_related("location_type", "parent", "tenant")
|
|
263
|
+
filterset_class = filters.LocationFilterSet
|
|
264
|
+
filterset_form_class = forms.LocationFilterForm
|
|
265
|
+
table_class = tables.LocationTable
|
|
266
|
+
form_class = forms.LocationForm
|
|
267
|
+
bulk_update_form_class = forms.LocationBulkEditForm
|
|
268
|
+
serializer_class = serializers.LocationSerializer
|
|
267
269
|
|
|
268
270
|
def get_extra_context(self, request, instance):
|
|
271
|
+
if instance is None:
|
|
272
|
+
return super().get_extra_context(request, instance)
|
|
269
273
|
related_locations = (
|
|
270
274
|
instance.descendants(include_self=True).restrict(request.user, "view").values_list("pk", flat=True)
|
|
271
275
|
)
|
|
@@ -305,7 +309,6 @@ class LocationView(generic.ObjectView):
|
|
|
305
309
|
)
|
|
306
310
|
|
|
307
311
|
children_table = tables.LocationTable(children, hide_hierarchy_ui=True)
|
|
308
|
-
|
|
309
312
|
paginate = {
|
|
310
313
|
"paginator_class": EnhancedPaginator,
|
|
311
314
|
"per_page": get_paginate_count(request),
|
|
@@ -323,34 +326,6 @@ class LocationView(generic.ObjectView):
|
|
|
323
326
|
}
|
|
324
327
|
|
|
325
328
|
|
|
326
|
-
class LocationEditView(generic.ObjectEditView):
|
|
327
|
-
queryset = Location.objects.all()
|
|
328
|
-
model_form = forms.LocationForm
|
|
329
|
-
template_name = "dcim/location_edit.html"
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
class LocationDeleteView(generic.ObjectDeleteView):
|
|
333
|
-
queryset = Location.objects.all()
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
class LocationBulkEditView(generic.BulkEditView):
|
|
337
|
-
queryset = Location.objects.select_related("location_type", "parent", "tenant")
|
|
338
|
-
filterset = filters.LocationFilterSet
|
|
339
|
-
table = tables.LocationTable
|
|
340
|
-
form = forms.LocationBulkEditForm
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
class LocationBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
|
|
344
|
-
queryset = Location.objects.all()
|
|
345
|
-
table = tables.LocationTable
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
class LocationBulkDeleteView(generic.BulkDeleteView):
|
|
349
|
-
queryset = Location.objects.select_related("location_type", "parent", "tenant")
|
|
350
|
-
filterset = filters.LocationFilterSet
|
|
351
|
-
table = tables.LocationTable
|
|
352
|
-
|
|
353
|
-
|
|
354
329
|
class MigrateLocationDataToContactView(generic.ObjectEditView):
|
|
355
330
|
queryset = Location.objects.all()
|
|
356
331
|
model_form = LocationMigrateDataToContactForm
|
|
@@ -1623,7 +1598,14 @@ class ModuleBayTemplateUIViewSet(
|
|
|
1623
1598
|
return parent.display
|
|
1624
1599
|
return ""
|
|
1625
1600
|
|
|
1626
|
-
@action(
|
|
1601
|
+
@action(
|
|
1602
|
+
detail=False,
|
|
1603
|
+
methods=["GET", "POST"],
|
|
1604
|
+
url_path="rename",
|
|
1605
|
+
url_name="bulk_rename",
|
|
1606
|
+
custom_view_base_action="change",
|
|
1607
|
+
custom_view_additional_permissions=["dcim.change_modulebaytemplate"],
|
|
1608
|
+
)
|
|
1627
1609
|
def bulk_rename(self, request, *args, **kwargs):
|
|
1628
1610
|
return self._bulk_rename(request, *args, **kwargs)
|
|
1629
1611
|
|
|
@@ -2393,35 +2375,6 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2393
2375
|
table_class = tables.ModuleTable
|
|
2394
2376
|
component_model = None
|
|
2395
2377
|
|
|
2396
|
-
def get_action(self):
|
|
2397
|
-
if self.component_model:
|
|
2398
|
-
method = self.request.method.lower()
|
|
2399
|
-
if method == "get":
|
|
2400
|
-
return "view"
|
|
2401
|
-
else:
|
|
2402
|
-
return "change"
|
|
2403
|
-
|
|
2404
|
-
return super().get_action()
|
|
2405
|
-
|
|
2406
|
-
def get_required_permission(self):
|
|
2407
|
-
# TODO: standardize a pattern for permissions enforcement on custom actions
|
|
2408
|
-
if self.component_model:
|
|
2409
|
-
model = self.component_model
|
|
2410
|
-
method = self.request.method.lower()
|
|
2411
|
-
if method == "get":
|
|
2412
|
-
component_action = "view"
|
|
2413
|
-
permissions = [*self.get_permissions_for_model(model, [component_action]), "dcim.view_module"]
|
|
2414
|
-
elif self.action.startswith("bulk_add"):
|
|
2415
|
-
component_action = "add"
|
|
2416
|
-
permissions = [*self.get_permissions_for_model(model, [component_action]), "dcim.change_module"]
|
|
2417
|
-
else:
|
|
2418
|
-
component_action = "change"
|
|
2419
|
-
permissions = [*self.get_permissions_for_model(model, [component_action]), "dcim.change_module"]
|
|
2420
|
-
|
|
2421
|
-
return permissions
|
|
2422
|
-
|
|
2423
|
-
return super().get_required_permission()
|
|
2424
|
-
|
|
2425
2378
|
def get_extra_context(self, request, instance):
|
|
2426
2379
|
context = super().get_extra_context(request, instance)
|
|
2427
2380
|
if instance:
|
|
@@ -2448,7 +2401,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2448
2401
|
|
|
2449
2402
|
return active_parent_tab
|
|
2450
2403
|
|
|
2451
|
-
@action(
|
|
2404
|
+
@action(
|
|
2405
|
+
detail=True,
|
|
2406
|
+
url_path="console-ports",
|
|
2407
|
+
component_model=ConsolePort,
|
|
2408
|
+
custom_view_base_action="view",
|
|
2409
|
+
custom_view_additional_permissions=["dcim.view_consoleport"],
|
|
2410
|
+
)
|
|
2452
2411
|
def consoleports(self, request, *args, **kwargs):
|
|
2453
2412
|
instance = self.get_object()
|
|
2454
2413
|
consoleports = (
|
|
@@ -2467,7 +2426,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2467
2426
|
}
|
|
2468
2427
|
)
|
|
2469
2428
|
|
|
2470
|
-
@action(
|
|
2429
|
+
@action(
|
|
2430
|
+
detail=True,
|
|
2431
|
+
url_path="console-server-ports",
|
|
2432
|
+
component_model=ConsoleServerPort,
|
|
2433
|
+
custom_view_base_action="view",
|
|
2434
|
+
custom_view_additional_permissions=["dcim.view_consoleserverport"],
|
|
2435
|
+
)
|
|
2471
2436
|
def consoleserverports(self, request, *args, **kwargs):
|
|
2472
2437
|
instance = self.get_object()
|
|
2473
2438
|
consoleserverports = (
|
|
@@ -2490,7 +2455,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2490
2455
|
}
|
|
2491
2456
|
)
|
|
2492
2457
|
|
|
2493
|
-
@action(
|
|
2458
|
+
@action(
|
|
2459
|
+
detail=True,
|
|
2460
|
+
url_path="power-ports",
|
|
2461
|
+
component_model=PowerPort,
|
|
2462
|
+
custom_view_base_action="view",
|
|
2463
|
+
custom_view_additional_permissions=["dcim.view_powerport"],
|
|
2464
|
+
)
|
|
2494
2465
|
def powerports(self, request, *args, **kwargs):
|
|
2495
2466
|
instance = self.get_object()
|
|
2496
2467
|
powerports = (
|
|
@@ -2511,7 +2482,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2511
2482
|
}
|
|
2512
2483
|
)
|
|
2513
2484
|
|
|
2514
|
-
@action(
|
|
2485
|
+
@action(
|
|
2486
|
+
detail=True,
|
|
2487
|
+
url_path="power-outlets",
|
|
2488
|
+
component_model=PowerOutlet,
|
|
2489
|
+
custom_view_base_action="view",
|
|
2490
|
+
custom_view_additional_permissions=["dcim.view_poweroutlet"],
|
|
2491
|
+
)
|
|
2515
2492
|
def poweroutlets(self, request, *args, **kwargs):
|
|
2516
2493
|
instance = self.get_object()
|
|
2517
2494
|
poweroutlets = (
|
|
@@ -2532,7 +2509,12 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2532
2509
|
}
|
|
2533
2510
|
)
|
|
2534
2511
|
|
|
2535
|
-
@action(
|
|
2512
|
+
@action(
|
|
2513
|
+
detail=True,
|
|
2514
|
+
component_model=Interface,
|
|
2515
|
+
custom_view_base_action="view",
|
|
2516
|
+
custom_view_additional_permissions=["dcim.view_interface"],
|
|
2517
|
+
)
|
|
2536
2518
|
def interfaces(self, request, *args, **kwargs):
|
|
2537
2519
|
instance = self.get_object()
|
|
2538
2520
|
interfaces = (
|
|
@@ -2558,7 +2540,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2558
2540
|
}
|
|
2559
2541
|
)
|
|
2560
2542
|
|
|
2561
|
-
@action(
|
|
2543
|
+
@action(
|
|
2544
|
+
detail=True,
|
|
2545
|
+
url_path="front-ports",
|
|
2546
|
+
component_model=FrontPort,
|
|
2547
|
+
custom_view_base_action="view",
|
|
2548
|
+
custom_view_additional_permissions=["dcim.view_frontport"],
|
|
2549
|
+
)
|
|
2562
2550
|
def frontports(self, request, *args, **kwargs):
|
|
2563
2551
|
instance = self.get_object()
|
|
2564
2552
|
frontports = instance.front_ports.restrict(request.user, "view").select_related("cable", "rear_port")
|
|
@@ -2575,7 +2563,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2575
2563
|
},
|
|
2576
2564
|
)
|
|
2577
2565
|
|
|
2578
|
-
@action(
|
|
2566
|
+
@action(
|
|
2567
|
+
detail=True,
|
|
2568
|
+
url_path="rear-ports",
|
|
2569
|
+
component_model=RearPort,
|
|
2570
|
+
custom_view_base_action="view",
|
|
2571
|
+
custom_view_additional_permissions=["dcim.view_rearport"],
|
|
2572
|
+
)
|
|
2579
2573
|
def rearports(self, request, *args, **kwargs):
|
|
2580
2574
|
instance = self.get_object()
|
|
2581
2575
|
rearports = instance.rear_ports.restrict(request.user, "view").select_related("cable")
|
|
@@ -2592,7 +2586,13 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2592
2586
|
}
|
|
2593
2587
|
)
|
|
2594
2588
|
|
|
2595
|
-
@action(
|
|
2589
|
+
@action(
|
|
2590
|
+
detail=True,
|
|
2591
|
+
url_path="module-bays",
|
|
2592
|
+
component_model=ModuleBay,
|
|
2593
|
+
custom_view_base_action="view",
|
|
2594
|
+
custom_view_additional_permissions=["dcim.view_modulebay"],
|
|
2595
|
+
)
|
|
2596
2596
|
def modulebays(self, request, *args, **kwargs):
|
|
2597
2597
|
instance = self.get_object()
|
|
2598
2598
|
modulebays = instance.module_bays.restrict(request.user, "view").prefetch_related(
|
|
@@ -2615,6 +2615,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2615
2615
|
url_path="console-ports/add",
|
|
2616
2616
|
url_name="bulk_add_consoleport",
|
|
2617
2617
|
component_model=ConsolePort,
|
|
2618
|
+
custom_view_base_action="change",
|
|
2619
|
+
custom_view_additional_permissions=["dcim.add_consoleport"],
|
|
2618
2620
|
)
|
|
2619
2621
|
def bulk_add_consoleport(self, request, *args, **kwargs):
|
|
2620
2622
|
return self._bulk_component_create(
|
|
@@ -2629,6 +2631,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2629
2631
|
url_path="console-server-ports/add",
|
|
2630
2632
|
url_name="bulk_add_consoleserverport",
|
|
2631
2633
|
component_model=ConsoleServerPort,
|
|
2634
|
+
custom_view_base_action="change",
|
|
2635
|
+
custom_view_additional_permissions=["dcim.add_consoleserverport"],
|
|
2632
2636
|
)
|
|
2633
2637
|
def bulk_add_consoleserverport(self, request, *args, **kwargs):
|
|
2634
2638
|
return self._bulk_component_create(
|
|
@@ -2643,6 +2647,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2643
2647
|
url_path="power-ports/add",
|
|
2644
2648
|
url_name="bulk_add_powerport",
|
|
2645
2649
|
component_model=PowerPort,
|
|
2650
|
+
custom_view_base_action="change",
|
|
2651
|
+
custom_view_additional_permissions=["dcim.add_powerport"],
|
|
2646
2652
|
)
|
|
2647
2653
|
def bulk_add_powerport(self, request, *args, **kwargs):
|
|
2648
2654
|
return self._bulk_component_create(
|
|
@@ -2657,6 +2663,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2657
2663
|
url_path="power-outlets/add",
|
|
2658
2664
|
url_name="bulk_add_poweroutlet",
|
|
2659
2665
|
component_model=PowerOutlet,
|
|
2666
|
+
custom_view_base_action="change",
|
|
2667
|
+
custom_view_additional_permissions=["dcim.add_poweroutlet"],
|
|
2660
2668
|
)
|
|
2661
2669
|
def bulk_add_poweroutlet(self, request, *args, **kwargs):
|
|
2662
2670
|
return self._bulk_component_create(
|
|
@@ -2671,6 +2679,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2671
2679
|
url_path="interfaces/add",
|
|
2672
2680
|
url_name="bulk_add_interface",
|
|
2673
2681
|
component_model=Interface,
|
|
2682
|
+
custom_view_base_action="change",
|
|
2683
|
+
custom_view_additional_permissions=["dcim.add_interface"],
|
|
2674
2684
|
)
|
|
2675
2685
|
def bulk_add_interface(self, request, *args, **kwargs):
|
|
2676
2686
|
return self._bulk_component_create(
|
|
@@ -2685,6 +2695,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2685
2695
|
url_path="rear-ports/add",
|
|
2686
2696
|
url_name="bulk_add_rearport",
|
|
2687
2697
|
component_model=RearPort,
|
|
2698
|
+
custom_view_base_action="change",
|
|
2699
|
+
custom_view_additional_permissions=["dcim.add_rearport"],
|
|
2688
2700
|
)
|
|
2689
2701
|
def bulk_add_rearport(self, request, *args, **kwargs):
|
|
2690
2702
|
return self._bulk_component_create(
|
|
@@ -2699,6 +2711,8 @@ class ModuleUIViewSet(BulkComponentCreateUIViewSetMixin, NautobotUIViewSet):
|
|
|
2699
2711
|
url_path="module-bays/add",
|
|
2700
2712
|
url_name="bulk_add_modulebay",
|
|
2701
2713
|
component_model=ModuleBay,
|
|
2714
|
+
custom_view_base_action="change",
|
|
2715
|
+
custom_view_additional_permissions=["dcim.add_modulebay"],
|
|
2702
2716
|
)
|
|
2703
2717
|
def bulk_add_modulebay(self, request, *args, **kwargs):
|
|
2704
2718
|
return self._bulk_component_create(
|
|
@@ -3394,7 +3408,6 @@ class ModuleBayUIViewSet(ModuleBayCommonViewSetMixin, NautobotUIViewSet):
|
|
|
3394
3408
|
serializer_class = serializers.ModuleBaySerializer
|
|
3395
3409
|
table_class = tables.ModuleBayTable
|
|
3396
3410
|
create_template_name = "dcim/device_component_add.html"
|
|
3397
|
-
|
|
3398
3411
|
object_detail_content = object_detail.ObjectDetailContent(
|
|
3399
3412
|
panels=(
|
|
3400
3413
|
object_detail.ObjectFieldsPanel(
|
|
@@ -3439,7 +3452,14 @@ class ModuleBayUIViewSet(ModuleBayCommonViewSetMixin, NautobotUIViewSet):
|
|
|
3439
3452
|
return parent.display
|
|
3440
3453
|
return ""
|
|
3441
3454
|
|
|
3442
|
-
@action(
|
|
3455
|
+
@action(
|
|
3456
|
+
detail=False,
|
|
3457
|
+
methods=["GET", "POST"],
|
|
3458
|
+
url_path="rename",
|
|
3459
|
+
url_name="bulk_rename",
|
|
3460
|
+
custom_view_base_action="change",
|
|
3461
|
+
custom_view_additional_permissions=["dcim.change_modulebay"],
|
|
3462
|
+
)
|
|
3443
3463
|
def bulk_rename(self, request, *args, **kwargs):
|
|
3444
3464
|
return self._bulk_rename(request, *args, **kwargs)
|
|
3445
3465
|
|
|
@@ -4159,6 +4179,28 @@ class PowerPanelUIViewSet(NautobotUIViewSet):
|
|
|
4159
4179
|
#
|
|
4160
4180
|
# Power feeds
|
|
4161
4181
|
#
|
|
4182
|
+
|
|
4183
|
+
|
|
4184
|
+
class CustomPowerFeedKeyValueTablePanel(object_detail.KeyValueTablePanel):
|
|
4185
|
+
"""Custom panel to render PowerFeed utilization graph cleanly."""
|
|
4186
|
+
|
|
4187
|
+
def render_value(self, key, value, context):
|
|
4188
|
+
if key == "Utilization (Allocated)":
|
|
4189
|
+
if not value or not isinstance(value, tuple) or len(value) != 2:
|
|
4190
|
+
return helpers.placeholder(None)
|
|
4191
|
+
allocated, available = value
|
|
4192
|
+
if available <= 0:
|
|
4193
|
+
return f"{allocated}VA / {available}VA"
|
|
4194
|
+
graph_html = render_to_string(
|
|
4195
|
+
"utilities/templatetags/utilization_graph.html",
|
|
4196
|
+
helpers.utilization_graph_raw_data(allocated, available),
|
|
4197
|
+
)
|
|
4198
|
+
return format_html("{}VA / {}VA {}", allocated, available, graph_html)
|
|
4199
|
+
|
|
4200
|
+
# Fall back to default behavior for everything else
|
|
4201
|
+
return super().render_value(key, value, context)
|
|
4202
|
+
|
|
4203
|
+
|
|
4162
4204
|
class PowerFeedUIViewSet(NautobotUIViewSet):
|
|
4163
4205
|
bulk_update_form_class = forms.PowerFeedBulkEditForm
|
|
4164
4206
|
filterset_class = filters.PowerFeedFilterSet
|
|
@@ -4168,6 +4210,137 @@ class PowerFeedUIViewSet(NautobotUIViewSet):
|
|
|
4168
4210
|
serializer_class = serializers.PowerFeedSerializer
|
|
4169
4211
|
table_class = tables.PowerFeedTable
|
|
4170
4212
|
|
|
4213
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
4214
|
+
panels=(
|
|
4215
|
+
CustomPowerFeedKeyValueTablePanel(
|
|
4216
|
+
section=SectionChoices.LEFT_HALF,
|
|
4217
|
+
weight=100,
|
|
4218
|
+
label="Power Feed",
|
|
4219
|
+
context_data_key="powerfeed_data",
|
|
4220
|
+
),
|
|
4221
|
+
object_detail.ObjectFieldsPanel(
|
|
4222
|
+
section=SectionChoices.LEFT_HALF,
|
|
4223
|
+
weight=200,
|
|
4224
|
+
label="Electrical Characteristics",
|
|
4225
|
+
fields=["supply", "voltage", "amperage", "phase", "max_utilization"],
|
|
4226
|
+
value_transforms={
|
|
4227
|
+
"voltage": [lambda v: f"{v}V" if v is not None else helpers.placeholder(v)],
|
|
4228
|
+
"amperage": [lambda a: f"{a}A" if a is not None else helpers.placeholder(a)],
|
|
4229
|
+
"max_utilization": [lambda p: f"{p}%" if p is not None else helpers.placeholder(p)],
|
|
4230
|
+
},
|
|
4231
|
+
),
|
|
4232
|
+
object_detail.KeyValueTablePanel(
|
|
4233
|
+
section=SectionChoices.RIGHT_HALF,
|
|
4234
|
+
weight=300,
|
|
4235
|
+
label="Connection",
|
|
4236
|
+
context_data_key="connection_data",
|
|
4237
|
+
),
|
|
4238
|
+
)
|
|
4239
|
+
)
|
|
4240
|
+
|
|
4241
|
+
def get_extra_context(self, request, instance):
|
|
4242
|
+
context = super().get_extra_context(request, instance)
|
|
4243
|
+
if not instance or self.action != "retrieve":
|
|
4244
|
+
return context
|
|
4245
|
+
|
|
4246
|
+
context["powerfeed_data"] = {
|
|
4247
|
+
"Power Panel": instance.power_panel,
|
|
4248
|
+
"Rack": instance.rack,
|
|
4249
|
+
"Type": self._get_type_html(instance), # Render Type with HTML label
|
|
4250
|
+
"Status": instance.status,
|
|
4251
|
+
"Connected Device": self._get_connected_device_html(instance),
|
|
4252
|
+
"Utilization (Allocated)": self._get_utilization_data(instance),
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4255
|
+
context["connection_data"] = self._get_connection_data(request, instance)
|
|
4256
|
+
return context
|
|
4257
|
+
|
|
4258
|
+
def _get_type_html(self, instance):
|
|
4259
|
+
"""
|
|
4260
|
+
Render the PowerFeed type as a label with the appropriate CSS class.
|
|
4261
|
+
"""
|
|
4262
|
+
|
|
4263
|
+
type_class = instance.get_type_class()
|
|
4264
|
+
return format_html('<span class="label label-{}">{}</span>', type_class, instance.get_type_display())
|
|
4265
|
+
|
|
4266
|
+
def _get_connected_device_html(self, instance):
|
|
4267
|
+
endpoint = getattr(instance, "connected_endpoint", None)
|
|
4268
|
+
if endpoint and endpoint.parent:
|
|
4269
|
+
parent = helpers.hyperlinked_object(endpoint.parent)
|
|
4270
|
+
return format_html("{} ({})", parent, endpoint)
|
|
4271
|
+
return None
|
|
4272
|
+
|
|
4273
|
+
def _get_utilization_data(self, instance):
|
|
4274
|
+
endpoint = getattr(instance, "connected_endpoint", None)
|
|
4275
|
+
if not endpoint or not hasattr(endpoint, "get_power_draw"):
|
|
4276
|
+
return None
|
|
4277
|
+
utilization = endpoint.get_power_draw()
|
|
4278
|
+
if not utilization or "allocated" not in utilization:
|
|
4279
|
+
return None
|
|
4280
|
+
allocated = utilization["allocated"]
|
|
4281
|
+
available = instance.available_power or 0
|
|
4282
|
+
return (allocated, available)
|
|
4283
|
+
|
|
4284
|
+
def _get_connection_data(self, request, instance):
|
|
4285
|
+
if not instance:
|
|
4286
|
+
return {}
|
|
4287
|
+
|
|
4288
|
+
if instance.cable:
|
|
4289
|
+
trace_url = reverse("dcim:powerfeed_trace", kwargs={"pk": instance.pk})
|
|
4290
|
+
cable_html = format_html(
|
|
4291
|
+
'{} <a href="{}" class="btn btn-primary btn-xs" title="Trace">'
|
|
4292
|
+
'<i class="mdi mdi-transit-connection-variant"></i></a>',
|
|
4293
|
+
helpers.hyperlinked_object(instance.cable),
|
|
4294
|
+
trace_url,
|
|
4295
|
+
)
|
|
4296
|
+
|
|
4297
|
+
endpoint = getattr(instance, "connected_endpoint", None)
|
|
4298
|
+
endpoint_data = {}
|
|
4299
|
+
|
|
4300
|
+
if endpoint:
|
|
4301
|
+
endpoint_obj = getattr(endpoint, "device", None) or getattr(endpoint, "module", None)
|
|
4302
|
+
# Removed the unused 'path' variable
|
|
4303
|
+
endpoint_data = {
|
|
4304
|
+
"Device" if getattr(endpoint, "device", None) else "Module": endpoint_obj,
|
|
4305
|
+
"Power Port": endpoint,
|
|
4306
|
+
"Type": endpoint.get_type_display() if hasattr(endpoint, "get_type_display") else None,
|
|
4307
|
+
"Description": endpoint.description,
|
|
4308
|
+
"Path Status": self._get_path_status_html(instance), # Render Path Status dynamically
|
|
4309
|
+
}
|
|
4310
|
+
|
|
4311
|
+
return {
|
|
4312
|
+
"Cable": cable_html,
|
|
4313
|
+
**endpoint_data,
|
|
4314
|
+
}
|
|
4315
|
+
|
|
4316
|
+
if request.user.has_perm("dcim.add_cable"):
|
|
4317
|
+
connect_url = (
|
|
4318
|
+
reverse(
|
|
4319
|
+
"dcim:powerfeed_connect",
|
|
4320
|
+
kwargs={"termination_a_id": instance.pk, "termination_b_type": "power-port"},
|
|
4321
|
+
)
|
|
4322
|
+
+ f"?return_url={instance.get_absolute_url()}"
|
|
4323
|
+
)
|
|
4324
|
+
connect_link = format_html(
|
|
4325
|
+
'<a href="{}" class="btn btn-primary btn-sm pull-right">'
|
|
4326
|
+
'<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> Connect</a>',
|
|
4327
|
+
connect_url,
|
|
4328
|
+
)
|
|
4329
|
+
return {"Connection": format_html("Not connected {}", connect_link)}
|
|
4330
|
+
|
|
4331
|
+
return {"Connection": "Not connected"}
|
|
4332
|
+
|
|
4333
|
+
def _get_path_status_html(self, instance):
|
|
4334
|
+
"""
|
|
4335
|
+
Render the Path Status as a label based on the path status (active or not).
|
|
4336
|
+
"""
|
|
4337
|
+
path_status = (
|
|
4338
|
+
'<span class="label label-success">Reachable</span>'
|
|
4339
|
+
if getattr(instance, "path", None) and instance.path.is_active
|
|
4340
|
+
else '<span class="label label-danger">Not Reachable</span>'
|
|
4341
|
+
)
|
|
4342
|
+
return format_html(path_status) # Safely render HTML
|
|
4343
|
+
|
|
4171
4344
|
|
|
4172
4345
|
class DeviceRedundancyGroupUIViewSet(NautobotUIViewSet):
|
|
4173
4346
|
bulk_update_form_class = forms.DeviceRedundancyGroupBulkEditForm
|
|
@@ -4218,38 +4391,35 @@ class InterfaceRedundancyGroupUIViewSet(NautobotUIViewSet):
|
|
|
4218
4391
|
table_class = tables.InterfaceRedundancyGroupTable
|
|
4219
4392
|
lookup_field = "pk"
|
|
4220
4393
|
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
for column_name in column_sequence:
|
|
4251
|
-
table.columns.show(column_name)
|
|
4252
|
-
return table
|
|
4394
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
4395
|
+
panels=(
|
|
4396
|
+
object_detail.ObjectFieldsPanel(
|
|
4397
|
+
weight=100,
|
|
4398
|
+
section=SectionChoices.LEFT_HALF,
|
|
4399
|
+
fields="__all__",
|
|
4400
|
+
),
|
|
4401
|
+
object_detail.ObjectsTablePanel(
|
|
4402
|
+
weight=200,
|
|
4403
|
+
section=SectionChoices.FULL_WIDTH,
|
|
4404
|
+
table_class=tables.InterfaceRedundancyGroupAssociationTable,
|
|
4405
|
+
table_attribute="interface_redundancy_group_associations",
|
|
4406
|
+
prefetch_related_fields=["interface"],
|
|
4407
|
+
order_by_fields=["priority"],
|
|
4408
|
+
table_title="Interfaces",
|
|
4409
|
+
related_field_name="interface_redundancy_group",
|
|
4410
|
+
include_columns=[
|
|
4411
|
+
"interface__device",
|
|
4412
|
+
"interface",
|
|
4413
|
+
"interface__status",
|
|
4414
|
+
"interface__enabled",
|
|
4415
|
+
"interface__ip_addresses",
|
|
4416
|
+
"interface__type",
|
|
4417
|
+
"interface__description",
|
|
4418
|
+
"interface__label",
|
|
4419
|
+
],
|
|
4420
|
+
),
|
|
4421
|
+
),
|
|
4422
|
+
)
|
|
4253
4423
|
|
|
4254
4424
|
|
|
4255
4425
|
class InterfaceRedundancyGroupAssociationUIViewSet(ObjectEditViewMixin, ObjectDestroyViewMixin):
|
|
@@ -4259,6 +4429,51 @@ class InterfaceRedundancyGroupAssociationUIViewSet(ObjectEditViewMixin, ObjectDe
|
|
|
4259
4429
|
lookup_field = "pk"
|
|
4260
4430
|
|
|
4261
4431
|
|
|
4432
|
+
class ModuleFamilyUIViewSet(NautobotUIViewSet):
|
|
4433
|
+
"""ViewSet for the ModuleFamily model."""
|
|
4434
|
+
|
|
4435
|
+
filterset_class = filters.ModuleFamilyFilterSet
|
|
4436
|
+
filterset_form_class = forms.ModuleFamilyFilterForm
|
|
4437
|
+
form_class = forms.ModuleFamilyForm
|
|
4438
|
+
bulk_update_form_class = forms.ModuleFamilyBulkEditForm
|
|
4439
|
+
queryset = ModuleFamily.objects.all()
|
|
4440
|
+
serializer_class = serializers.ModuleFamilySerializer
|
|
4441
|
+
table_class = tables.ModuleFamilyTable
|
|
4442
|
+
lookup_field = "pk"
|
|
4443
|
+
|
|
4444
|
+
def get_extra_context(self, request, instance):
|
|
4445
|
+
context = super().get_extra_context(request, instance)
|
|
4446
|
+
if not instance:
|
|
4447
|
+
return context
|
|
4448
|
+
|
|
4449
|
+
if self.action == "retrieve":
|
|
4450
|
+
module_types = (
|
|
4451
|
+
ModuleType.objects.restrict(request.user, "view")
|
|
4452
|
+
.filter(module_family=instance)
|
|
4453
|
+
.select_related("manufacturer")
|
|
4454
|
+
)
|
|
4455
|
+
module_type_table = tables.ModuleTypeTable(module_types, orderable=False)
|
|
4456
|
+
|
|
4457
|
+
module_bays = (
|
|
4458
|
+
ModuleBay.objects.restrict(request.user, "view")
|
|
4459
|
+
.filter(module_family=instance)
|
|
4460
|
+
.select_related("parent_device", "parent_module")
|
|
4461
|
+
)
|
|
4462
|
+
module_bay_table = tables.ModuleBayTable(module_bays, orderable=False)
|
|
4463
|
+
|
|
4464
|
+
paginate = {
|
|
4465
|
+
"paginator_class": EnhancedPaginator,
|
|
4466
|
+
"per_page": get_paginate_count(request),
|
|
4467
|
+
}
|
|
4468
|
+
RequestConfig(request, paginate).configure(module_type_table)
|
|
4469
|
+
RequestConfig(request, paginate).configure(module_bay_table)
|
|
4470
|
+
|
|
4471
|
+
context["module_type_table"] = module_type_table
|
|
4472
|
+
context["module_bay_table"] = module_bay_table
|
|
4473
|
+
|
|
4474
|
+
return context
|
|
4475
|
+
|
|
4476
|
+
|
|
4262
4477
|
class DeviceFamilyUIViewSet(NautobotUIViewSet):
|
|
4263
4478
|
filterset_class = filters.DeviceFamilyFilterSet
|
|
4264
4479
|
filterset_form_class = forms.DeviceFamilyFilterForm
|
|
@@ -4308,7 +4523,6 @@ class SoftwareImageFileUIViewSet(NautobotUIViewSet):
|
|
|
4308
4523
|
queryset = SoftwareImageFile.objects.all()
|
|
4309
4524
|
serializer_class = serializers.SoftwareImageFileSerializer
|
|
4310
4525
|
table_class = tables.SoftwareImageFileTable
|
|
4311
|
-
|
|
4312
4526
|
object_detail_content = object_detail.ObjectDetailContent(
|
|
4313
4527
|
panels=(
|
|
4314
4528
|
object_detail.ObjectFieldsPanel(
|
|
@@ -4392,19 +4606,42 @@ class SoftwareImageFileUIViewSet(NautobotUIViewSet):
|
|
|
4392
4606
|
),
|
|
4393
4607
|
)
|
|
4394
4608
|
|
|
4395
|
-
@action(
|
|
4609
|
+
@action(
|
|
4610
|
+
detail=True,
|
|
4611
|
+
url_path="device-types",
|
|
4612
|
+
url_name="device_types",
|
|
4613
|
+
custom_view_base_action="view",
|
|
4614
|
+
custom_view_additional_permissions=["dcim.view_devicetype"],
|
|
4615
|
+
)
|
|
4396
4616
|
def device_types(self, request, *args, **kwargs):
|
|
4397
4617
|
return Response({})
|
|
4398
4618
|
|
|
4399
|
-
@action(
|
|
4619
|
+
@action(
|
|
4620
|
+
detail=True,
|
|
4621
|
+
url_path="devices",
|
|
4622
|
+
custom_view_base_action="view",
|
|
4623
|
+
custom_view_additional_permissions=["dcim.view_device"],
|
|
4624
|
+
)
|
|
4400
4625
|
def devices(self, request, *args, **kwargs):
|
|
4401
4626
|
return Response({})
|
|
4402
4627
|
|
|
4403
|
-
@action(
|
|
4628
|
+
@action(
|
|
4629
|
+
detail=True,
|
|
4630
|
+
url_path="inventory-items",
|
|
4631
|
+
url_name="inventory_items",
|
|
4632
|
+
custom_view_base_action="view",
|
|
4633
|
+
custom_view_additional_permissions=["dcim.view_inventoryitem"],
|
|
4634
|
+
)
|
|
4404
4635
|
def inventory_items(self, request, *args, **kwargs):
|
|
4405
4636
|
return Response({})
|
|
4406
4637
|
|
|
4407
|
-
@action(
|
|
4638
|
+
@action(
|
|
4639
|
+
detail=True,
|
|
4640
|
+
url_path="virtual-machines",
|
|
4641
|
+
url_name="virtual_machines",
|
|
4642
|
+
custom_view_base_action="view",
|
|
4643
|
+
custom_view_additional_permissions=["virtualization.view_virtualmachine"],
|
|
4644
|
+
)
|
|
4408
4645
|
def virtual_machines(self, request, *args, **kwargs):
|
|
4409
4646
|
return Response({})
|
|
4410
4647
|
|
|
@@ -4470,7 +4707,14 @@ class ControllerUIViewSet(NautobotUIViewSet):
|
|
|
4470
4707
|
|
|
4471
4708
|
return context
|
|
4472
4709
|
|
|
4473
|
-
@action(
|
|
4710
|
+
@action(
|
|
4711
|
+
detail=True,
|
|
4712
|
+
url_path="wireless-networks",
|
|
4713
|
+
url_name="wirelessnetworks",
|
|
4714
|
+
methods=["get"],
|
|
4715
|
+
custom_view_base_action="view",
|
|
4716
|
+
custom_view_additional_permissions=["wireless.view_controllermanageddevicegroupwirelessnetworkassignment"],
|
|
4717
|
+
)
|
|
4474
4718
|
def wirelessnetworks(self, request, *args, **kwargs):
|
|
4475
4719
|
instance = self.get_object()
|
|
4476
4720
|
controller_managed_device_groups = instance.controller_managed_device_groups.restrict(
|
|
@@ -4495,10 +4739,6 @@ class ControllerUIViewSet(NautobotUIViewSet):
|
|
|
4495
4739
|
}
|
|
4496
4740
|
)
|
|
4497
4741
|
|
|
4498
|
-
def get_action(self):
|
|
4499
|
-
"Treat Wireless Networks as the same detail view for permission purposes."
|
|
4500
|
-
return "view" if self.action == "wirelessnetworks" else super().get_action()
|
|
4501
|
-
|
|
4502
4742
|
|
|
4503
4743
|
class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
|
|
4504
4744
|
filterset_class = filters.ControllerManagedDeviceGroupFilterSet
|
|
@@ -4509,42 +4749,88 @@ class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
|
|
|
4509
4749
|
serializer_class = serializers.ControllerManagedDeviceGroupSerializer
|
|
4510
4750
|
table_class = tables.ControllerManagedDeviceGroupTable
|
|
4511
4751
|
template_name = "dcim/controllermanageddevicegroup_create.html"
|
|
4752
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
4753
|
+
panels=(
|
|
4754
|
+
object_detail.ObjectFieldsPanel(
|
|
4755
|
+
section=SectionChoices.LEFT_HALF,
|
|
4756
|
+
weight=100,
|
|
4757
|
+
fields="__all__",
|
|
4758
|
+
value_transforms={
|
|
4759
|
+
"capabilities": [helpers.label_list],
|
|
4760
|
+
},
|
|
4761
|
+
),
|
|
4762
|
+
object_detail.ObjectsTablePanel(
|
|
4763
|
+
section=SectionChoices.FULL_WIDTH,
|
|
4764
|
+
weight=100,
|
|
4765
|
+
table_class=tables.DeviceTable,
|
|
4766
|
+
table_filter="controller_managed_device_group",
|
|
4767
|
+
add_button_route=None,
|
|
4768
|
+
),
|
|
4769
|
+
),
|
|
4770
|
+
extra_tabs=(
|
|
4771
|
+
object_detail.DistinctViewTab(
|
|
4772
|
+
weight=800,
|
|
4773
|
+
tab_id="wireless_networks",
|
|
4774
|
+
label="Wireless Networks",
|
|
4775
|
+
url_name="dcim:controllermanageddevicegroup_wireless_networks",
|
|
4776
|
+
related_object_attribute="wireless_network_assignments",
|
|
4777
|
+
panels=(
|
|
4778
|
+
object_detail.ObjectsTablePanel(
|
|
4779
|
+
section=SectionChoices.FULL_WIDTH,
|
|
4780
|
+
weight=100,
|
|
4781
|
+
table_title="Wireless Networks",
|
|
4782
|
+
table_class=DeviceGroupWirelessNetworkTable,
|
|
4783
|
+
table_filter="controller_managed_device_group",
|
|
4784
|
+
related_field_name="controller_managed_device_groups",
|
|
4785
|
+
tab_id="wireless_networks",
|
|
4786
|
+
add_button_route=None,
|
|
4787
|
+
exclude_columns=["controller_managed_device_group", "controller"],
|
|
4788
|
+
),
|
|
4789
|
+
),
|
|
4790
|
+
),
|
|
4791
|
+
object_detail.DistinctViewTab(
|
|
4792
|
+
weight=900,
|
|
4793
|
+
tab_id="radio_profiles",
|
|
4794
|
+
label="Radio Profiles",
|
|
4795
|
+
url_name="dcim:controllermanageddevicegroup_radio_profiles",
|
|
4796
|
+
related_object_attribute="radio_profiles",
|
|
4797
|
+
panels=(
|
|
4798
|
+
object_detail.ObjectsTablePanel(
|
|
4799
|
+
section=SectionChoices.FULL_WIDTH,
|
|
4800
|
+
weight=100,
|
|
4801
|
+
table_title="Radio Profiles",
|
|
4802
|
+
table_class=RadioProfileTable,
|
|
4803
|
+
table_filter="controller_managed_device_groups",
|
|
4804
|
+
tab_id="radio_profiles",
|
|
4805
|
+
add_button_route=None,
|
|
4806
|
+
),
|
|
4807
|
+
),
|
|
4808
|
+
),
|
|
4809
|
+
),
|
|
4810
|
+
)
|
|
4512
4811
|
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
"per_page": get_paginate_count(request),
|
|
4523
|
-
}
|
|
4524
|
-
RequestConfig(request, paginate).configure(devices_table)
|
|
4525
|
-
|
|
4526
|
-
context["devices_table"] = devices_table
|
|
4812
|
+
@action(
|
|
4813
|
+
detail=True,
|
|
4814
|
+
url_path="wireless-networks",
|
|
4815
|
+
url_name="wireless_networks",
|
|
4816
|
+
custom_view_base_action="view",
|
|
4817
|
+
custom_view_additional_permissions=["wireless.view_controllermanageddevicegroupwirelessnetworkassignment"],
|
|
4818
|
+
)
|
|
4819
|
+
def wireless_networks(self, request, *args, **kwargs):
|
|
4820
|
+
return Response({})
|
|
4527
4821
|
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
context["wireless_networks_count"] = wireless_networks.count()
|
|
4538
|
-
|
|
4539
|
-
# Radio Profiles
|
|
4540
|
-
radio_profiles = instance.radio_profiles.restrict(request.user, "view")
|
|
4541
|
-
radio_profiles_table = RadioProfileTable(radio_profiles)
|
|
4542
|
-
RequestConfig(
|
|
4543
|
-
request, paginate={"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
|
|
4544
|
-
).configure(radio_profiles_table)
|
|
4545
|
-
context["radio_profiles_table"] = radio_profiles_table
|
|
4546
|
-
context["radio_profiles_count"] = radio_profiles.count()
|
|
4822
|
+
@action(
|
|
4823
|
+
detail=True,
|
|
4824
|
+
url_path="radio-profiles",
|
|
4825
|
+
url_name="radio_profiles",
|
|
4826
|
+
custom_view_base_action="view",
|
|
4827
|
+
custom_view_additional_permissions=["wireless.view_radioprofile"],
|
|
4828
|
+
)
|
|
4829
|
+
def radio_profiles(self, request, *args, **kwargs):
|
|
4830
|
+
return Response({})
|
|
4547
4831
|
|
|
4832
|
+
def get_extra_context(self, request, instance):
|
|
4833
|
+
context = super().get_extra_context(request, instance)
|
|
4548
4834
|
if self.action in ["create", "update"]:
|
|
4549
4835
|
context["wireless_networks"] = ControllerManagedDeviceGroupWirelessNetworkFormSet(
|
|
4550
4836
|
instance=instance,
|