nautobot 2.4.18__py3-none-any.whl → 2.4.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/ui.py +6 -0
- nautobot/circuits/tables.py +1 -1
- nautobot/circuits/templates/circuits/circuit_create.html +7 -7
- nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -5
- nautobot/circuits/templates/circuits/circuittermination_create.html +26 -26
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +20 -20
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +3 -3
- nautobot/circuits/templates/circuits/inc/circuit_termination_speed_fragment.html +7 -7
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +1 -3
- nautobot/circuits/views.py +26 -9
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +1 -4
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +1 -3
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +1 -5
- nautobot/cloud/views.py +45 -0
- nautobot/core/graphql/generators.py +5 -2
- nautobot/core/jobs/bulk_actions.py +48 -85
- nautobot/core/models/querysets.py +2 -1
- nautobot/core/templates/40x.html +15 -15
- nautobot/core/templates/500.html +21 -21
- nautobot/core/templates/admin/app_index.html +8 -8
- nautobot/core/templates/admin/base.html +104 -104
- nautobot/core/templates/admin/change_form.html +65 -65
- nautobot/core/templates/admin/change_list.html +60 -60
- nautobot/core/templates/admin/change_list_results.html +39 -39
- nautobot/core/templates/admin/config/config.html +47 -47
- nautobot/core/templates/admin/delete_confirmation.html +47 -47
- nautobot/core/templates/admin/edit_inline/stacked.html +124 -124
- nautobot/core/templates/admin/edit_inline/tabular.html +60 -60
- nautobot/core/templates/admin/includes/fieldset.html +4 -4
- nautobot/core/templates/admin/index.html +60 -60
- nautobot/core/templates/admin/prepopulated_fields_js.html +18 -18
- nautobot/core/templates/admin/submit_line.html +4 -4
- nautobot/core/templates/base_django.html +46 -46
- nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +8 -8
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +8 -8
- nautobot/core/templates/buttons/export.html +3 -3
- nautobot/core/templates/components/breadcrumbs.html +5 -5
- nautobot/core/templates/components/button/default.html +3 -3
- nautobot/core/templates/components/button/dropdown.html +7 -7
- nautobot/core/templates/components/button/formbutton.html +4 -4
- nautobot/core/templates/components/panel/body_content_data_table.html +1 -1
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +3 -0
- nautobot/core/templates/components/panel/footer_content_table.html +3 -1
- nautobot/core/templates/components/panel/header_extra_content_table.html +10 -1
- nautobot/core/templates/components/tab/content_wrapper.html +1 -1
- nautobot/core/templates/components/tab/label_wrapper.html +1 -1
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +10 -3
- nautobot/core/templates/generic/object_bulk_add_component.html +40 -40
- nautobot/core/templates/generic/object_bulk_create.html +3 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +6 -6
- nautobot/core/templates/generic/object_bulk_update.html +52 -52
- nautobot/core/templates/generic/object_import.html +33 -33
- nautobot/core/templates/generic/object_list.html +267 -267
- nautobot/core/templates/generic/object_retrieve.html +261 -261
- nautobot/core/templates/graphene/graphiql.html +127 -127
- nautobot/core/templates/home.html +62 -62
- nautobot/core/templates/inc/computed_fields/panel_data.html +13 -13
- nautobot/core/templates/inc/created_updated.html +8 -8
- nautobot/core/templates/inc/custom_fields/panel_data.html +13 -13
- nautobot/core/templates/inc/dynamic_groups_panel.html +11 -11
- nautobot/core/templates/inc/footer.html +19 -19
- nautobot/core/templates/inc/javascript.html +1 -1
- nautobot/core/templates/inc/media.html +46 -46
- nautobot/core/templates/inc/nav_menu.html +1 -1
- nautobot/core/templates/inc/relationships_table_rows.html +22 -22
- nautobot/core/templates/inc/tenant_table_row.html +1 -1
- nautobot/core/templates/login.html +77 -77
- nautobot/core/templates/media_failure.html +38 -38
- nautobot/core/templates/panel_table.html +1 -1
- nautobot/core/templates/rest_framework/api.html +3 -3
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +9 -9
- nautobot/core/templates/utilities/confirmation_form.html +18 -18
- nautobot/core/templates/utilities/render_field.html +1 -1
- nautobot/core/templates/utilities/render_jinja2.html +43 -43
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +56 -56
- nautobot/core/templates/utilities/templatetags/utilization_graph.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +799 -799
- nautobot/core/templates/utilities/worker_status.html +122 -122
- nautobot/core/templates/widgets/clearable_file.html +3 -3
- nautobot/core/templates/widgets/sluginput.html +1 -1
- nautobot/core/templatetags/buttons.py +8 -2
- nautobot/core/templatetags/helpers.py +1 -1
- nautobot/core/testing/integration.py +7 -4
- nautobot/core/testing/views.py +24 -5
- nautobot/core/tests/test_breadcrumbs.py +78 -4
- nautobot/core/tests/test_commands.py +7 -4
- nautobot/core/tests/test_graphql.py +20 -5
- nautobot/core/tests/test_jobs.py +34 -21
- nautobot/core/tests/test_ui.py +175 -1
- nautobot/core/tests/test_utils.py +35 -0
- nautobot/core/tests/test_views_generic.py +43 -0
- nautobot/core/tests/test_views_utils.py +239 -5
- nautobot/core/ui/breadcrumbs.py +208 -21
- nautobot/core/ui/bulk_buttons.py +8 -0
- nautobot/core/ui/object_detail.py +138 -55
- nautobot/core/ui/titles.py +1 -0
- nautobot/core/utils/requests.py +27 -2
- nautobot/core/views/generic.py +41 -31
- nautobot/core/views/mixins.py +80 -110
- nautobot/core/views/utils.py +153 -1
- nautobot/dcim/api/serializers.py +8 -2
- nautobot/dcim/constants.py +1 -0
- nautobot/dcim/factory.py +4 -3
- nautobot/dcim/filters/mixins.py +1 -2
- nautobot/dcim/forms.py +5 -1
- nautobot/dcim/migrations/0074_alter_rack_u_height.py +21 -0
- nautobot/dcim/models/devices.py +26 -1
- nautobot/dcim/models/racks.py +2 -2
- nautobot/dcim/templates/dcim/cable.html +53 -53
- nautobot/dcim/templates/dcim/cable_connect.html +182 -182
- nautobot/dcim/templates/dcim/cable_trace.html +1 -1
- nautobot/dcim/templates/dcim/console_port_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/consoleport.html +86 -86
- nautobot/dcim/templates/dcim/consoleserverport.html +86 -86
- nautobot/dcim/templates/dcim/controller_create.html +34 -34
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -68
- nautobot/dcim/templates/dcim/device/base.html +1 -104
- nautobot/dcim/templates/dcim/device/config.html +17 -17
- nautobot/dcim/templates/dcim/device/consoleports.html +1 -52
- nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -52
- nautobot/dcim/templates/dcim/device/devicebays.html +1 -48
- nautobot/dcim/templates/dcim/device/frontports.html +1 -52
- nautobot/dcim/templates/dcim/device/interfaces.html +1 -56
- nautobot/dcim/templates/dcim/device/inventory.html +1 -48
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +64 -64
- nautobot/dcim/templates/dcim/device/modulebays.html +1 -48
- nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -52
- nautobot/dcim/templates/dcim/device/powerports.html +1 -52
- nautobot/dcim/templates/dcim/device/rearports.html +1 -52
- nautobot/dcim/templates/dcim/device/status.html +66 -66
- nautobot/dcim/templates/dcim/device/wireless.html +1 -72
- nautobot/dcim/templates/dcim/device.html +4 -422
- nautobot/dcim/templates/dcim/device_component_add.html +25 -25
- nautobot/dcim/templates/dcim/device_create.html +229 -0
- nautobot/dcim/templates/dcim/device_edit.html +2 -227
- nautobot/dcim/templates/dcim/devicebay.html +41 -41
- nautobot/dcim/templates/dcim/devicebay_populate.html +32 -32
- nautobot/dcim/templates/dcim/devicetype_component_add.html +28 -28
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -3
- nautobot/dcim/templates/dcim/frontport.html +84 -84
- nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
- nautobot/dcim/templates/dcim/inc/device_interface_filter.html +8 -0
- nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +1 -15
- nautobot/dcim/templates/dcim/inc/location_hierarchy.html +22 -22
- nautobot/dcim/templates/dcim/interface.html +206 -206
- nautobot/dcim/templates/dcim/interface_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/interfaceredundancygroupassociation_create.html +6 -6
- nautobot/dcim/templates/dcim/inventoryitem.html +44 -44
- nautobot/dcim/templates/dcim/inventoryitem_add.html +32 -32
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +22 -22
- nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +46 -46
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +1 -6
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -7
- nautobot/dcim/templates/dcim/module/base.html +85 -85
- nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
- nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
- nautobot/dcim/templates/dcim/module_retrieve.html +52 -52
- nautobot/dcim/templates/dcim/module_update.html +61 -61
- nautobot/dcim/templates/dcim/modulebay_destroy.html +1 -1
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +85 -85
- nautobot/dcim/templates/dcim/modulebay_update.html +33 -33
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +140 -144
- nautobot/dcim/templates/dcim/platform_create.html +38 -38
- nautobot/dcim/templates/dcim/power_port_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -8
- nautobot/dcim/templates/dcim/poweroutlet.html +85 -85
- nautobot/dcim/templates/dcim/powerpanel_retrieve.html +1 -8
- nautobot/dcim/templates/dcim/powerport.html +91 -91
- nautobot/dcim/templates/dcim/rack_elevation_list.html +18 -18
- nautobot/dcim/templates/dcim/rack_retrieve.html +264 -274
- nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -3
- nautobot/dcim/templates/dcim/rearport.html +78 -78
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -5
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +3 -2
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +6 -2
- nautobot/dcim/tests/test_api.py +33 -1
- nautobot/dcim/tests/test_views.py +148 -4
- nautobot/dcim/ui.py +29 -0
- nautobot/dcim/urls.py +1 -109
- nautobot/dcim/utils.py +30 -0
- nautobot/dcim/views.py +1009 -531
- nautobot/extras/tables.py +20 -0
- nautobot/extras/templates/extras/computedfield_edit.html +4 -4
- nautobot/extras/templates/extras/configcontext_update.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_retrieve.html +32 -32
- nautobot/extras/templates/extras/customfield_update.html +23 -23
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +38 -38
- nautobot/extras/templates/extras/dynamicgroup_update.html +62 -62
- nautobot/extras/templates/extras/gitrepository_list.html +10 -10
- nautobot/extras/templates/extras/gitrepository_retrieve.html +68 -68
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +73 -73
- nautobot/extras/templates/extras/inc/configcontext_format.html +2 -2
- nautobot/extras/templates/extras/inc/job_table.html +10 -10
- nautobot/extras/templates/extras/inc/jobresult.html +21 -21
- nautobot/extras/templates/extras/inc/jobresult_js.html +6 -6
- nautobot/extras/templates/extras/inc/tags_panel.html +10 -10
- nautobot/extras/templates/extras/job.html +64 -64
- nautobot/extras/templates/extras/job_approval_request.html +9 -9
- nautobot/extras/templates/extras/job_bulk_edit.html +13 -13
- nautobot/extras/templates/extras/job_edit.html +45 -45
- nautobot/extras/templates/extras/job_list.html +4 -4
- nautobot/extras/templates/extras/jobresult_retrieve.html +0 -25
- nautobot/extras/templates/extras/marketplace.html +101 -101
- nautobot/extras/templates/extras/metadatatype_create.html +20 -20
- nautobot/extras/templates/extras/object_assign_contact_or_team.html +18 -18
- nautobot/extras/templates/extras/object_configcontext.html +1 -3
- nautobot/extras/templates/extras/objectchange.html +2 -165
- nautobot/extras/templates/extras/objectchange_retrieve.html +165 -0
- nautobot/extras/templates/extras/plugin_detail.html +41 -41
- nautobot/extras/templates/extras/plugins_list.html +9 -9
- nautobot/extras/templates/extras/plugins_tiles.html +26 -26
- nautobot/extras/templates/extras/relationship_edit.html +4 -4
- nautobot/extras/templates/extras/role_retrieve.html +13 -13
- nautobot/extras/templates/extras/scheduled_jobs_approval_queue_list.html +21 -21
- nautobot/extras/templates/extras/scheduledjob.html +128 -128
- nautobot/extras/templates/extras/secret_create.html +53 -53
- nautobot/extras/templates/extras/secretsgroup_update.html +13 -13
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +3 -3
- nautobot/extras/templates/extras/webhook.html +79 -79
- nautobot/extras/tests/integration/test_relationships.py +6 -6
- nautobot/extras/tests/test_filters.py +1 -1
- nautobot/extras/tests/test_jobs.py +2 -0
- nautobot/extras/tests/test_views.py +3 -3
- nautobot/extras/urls.py +1 -3
- nautobot/extras/views.py +101 -27
- nautobot/ipam/filters.py +2 -2
- nautobot/ipam/migrations/0053_alter_vrfdeviceassignment_options_and_more.py +20 -0
- nautobot/ipam/models.py +34 -0
- nautobot/ipam/tables.py +3 -1
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +4 -0
- nautobot/ipam/templates/ipam/inc/toggle_available.html +8 -8
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +4 -4
- nautobot/ipam/templates/ipam/ipaddress.html +119 -123
- nautobot/ipam/templates/ipam/ipaddress_assign.html +10 -10
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -1
- nautobot/ipam/templates/ipam/ipaddress_merge.html +180 -180
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +48 -48
- nautobot/ipam/templates/ipam/prefix.html +2 -107
- nautobot/ipam/templates/ipam/prefix_create.html +34 -0
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -34
- nautobot/ipam/templates/ipam/prefix_retrieve.html +3 -0
- nautobot/ipam/templates/ipam/service_retrieve.html +1 -6
- nautobot/ipam/templates/ipam/vlan_retrieve.html +1 -7
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -1
- nautobot/ipam/tests/test_views.py +34 -0
- nautobot/ipam/ui.py +145 -0
- nautobot/ipam/urls.py +1 -46
- nautobot/ipam/utils/__init__.py +26 -0
- nautobot/ipam/views.py +219 -106
- nautobot/project-static/docs/404.html +11 -11
- nautobot/project-static/docs/apps/index.html +11 -11
- nautobot/project-static/docs/apps/nautobot-apps.html +11 -11
- nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js → bundle.f55a23d4.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js.map → bundle.f55a23d4.min.js.map} +2 -2
- nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css → main.e53b48f4.min.css} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css.map → main.e53b48f4.min.css.map} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2174 -1226
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +12 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +72 -27
- nautobot/project-static/docs/development/apps/api/configuration-view.html +11 -11
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/global-search.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/graphql.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/prepopulating-data.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +11 -11
- nautobot/project-static/docs/development/apps/api/prometheus.html +11 -11
- nautobot/project-static/docs/development/apps/api/setup.html +11 -11
- nautobot/project-static/docs/development/apps/api/testing.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/base-template.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/notes.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/urls.html +11 -11
- nautobot/project-static/docs/development/apps/index.html +11 -11
- nautobot/project-static/docs/development/apps/migration/code-updates.html +11 -11
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +11 -11
- nautobot/project-static/docs/development/apps/migration/from-v1.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +11 -11
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +11 -11
- nautobot/project-static/docs/development/core/application-registry.html +11 -11
- nautobot/project-static/docs/development/core/best-practices.html +11 -11
- nautobot/project-static/docs/development/core/bootstrap-ui.html +11 -11
- nautobot/project-static/docs/development/core/caching.html +11 -11
- nautobot/project-static/docs/development/core/controllers.html +11 -11
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +11 -11
- nautobot/project-static/docs/development/core/generic-views.html +11 -11
- nautobot/project-static/docs/development/core/getting-started.html +50 -48
- nautobot/project-static/docs/development/core/homepage.html +11 -11
- nautobot/project-static/docs/development/core/index.html +11 -11
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +11 -11
- nautobot/project-static/docs/development/core/model-checklist.html +11 -11
- nautobot/project-static/docs/development/core/model-features.html +11 -11
- nautobot/project-static/docs/development/core/natural-keys.html +11 -11
- nautobot/project-static/docs/development/core/navigation-menu.html +11 -11
- nautobot/project-static/docs/development/core/release-checklist.html +11 -11
- nautobot/project-static/docs/development/core/role-internals.html +11 -11
- nautobot/project-static/docs/development/core/settings.html +11 -11
- nautobot/project-static/docs/development/core/style-guide.html +15 -11
- nautobot/project-static/docs/development/core/templates.html +11 -11
- nautobot/project-static/docs/development/core/testing.html +11 -11
- nautobot/project-static/docs/development/core/ui-component-framework.html +11 -11
- nautobot/project-static/docs/development/core/user-preferences.html +11 -11
- nautobot/project-static/docs/development/index.html +11 -11
- nautobot/project-static/docs/development/jobs/getting-started.html +11 -11
- nautobot/project-static/docs/development/jobs/index.html +11 -11
- nautobot/project-static/docs/development/jobs/installation.html +11 -11
- nautobot/project-static/docs/development/jobs/job-extensions.html +11 -11
- nautobot/project-static/docs/development/jobs/job-logging.html +11 -11
- nautobot/project-static/docs/development/jobs/job-patterns.html +11 -11
- nautobot/project-static/docs/development/jobs/job-structure.html +11 -11
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +11 -11
- nautobot/project-static/docs/development/jobs/testing.html +11 -11
- nautobot/project-static/docs/index.html +11 -11
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +11 -11
- nautobot/project-static/docs/overview/design_philosophy.html +11 -11
- nautobot/project-static/docs/release-notes/index.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.0.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.1.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.2.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.3.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.4.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.5.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.6.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.0.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.1.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.2.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.3.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.4.html +196 -11
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +300 -300
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +89 -14
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/services.html +11 -11
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +11 -11
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +11 -11
- nautobot/project-static/docs/user-guide/administration/security/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/security/notices.html +11 -11
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +11 -11
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +11 -11
- nautobot/project-static/docs/user-guide/index.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +11 -11
- nautobot/tenancy/templates/tenancy/tenant.html +1 -7
- nautobot/tenancy/views.py +13 -0
- nautobot/users/templates/users/api_tokens.html +4 -4
- nautobot/users/templates/users/base.html +28 -28
- nautobot/virtualization/templates/virtualization/cluster.html +64 -64
- nautobot/virtualization/templates/virtualization/inc/virtualmachine_vminterface_filter.html +8 -0
- nautobot/virtualization/templates/virtualization/virtualmachine_component_add.html +25 -25
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +1 -251
- nautobot/virtualization/templates/virtualization/vminterface.html +70 -70
- nautobot/virtualization/urls.py +0 -12
- nautobot/virtualization/views.py +158 -54
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +13 -13
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -1
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/METADATA +1 -1
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/RECORD +581 -570
- nautobot/ipam/templates/ipam/prefix_ipaddresses.html +0 -11
- nautobot/ipam/templates/ipam/prefix_prefixes.html +0 -11
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/NOTICE +0 -0
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/WHEEL +0 -0
- {nautobot-2.4.18.dist-info → nautobot-2.4.19.dist-info}/entry_points.txt +0 -0
|
@@ -43,9 +43,11 @@ from nautobot.core.utils.lookup import get_filterset_for_model, get_route_for_mo
|
|
|
43
43
|
from nautobot.core.utils.permissions import get_permission_for_model
|
|
44
44
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
45
45
|
from nautobot.core.views.utils import get_obj_from_context
|
|
46
|
+
from nautobot.dcim.models import Rack
|
|
46
47
|
from nautobot.extras.choices import CustomFieldTypeChoices
|
|
47
48
|
from nautobot.extras.tables import AssociatedContactsTable, DynamicGroupTable, ObjectMetadataTable
|
|
48
49
|
from nautobot.tenancy.models import Tenant
|
|
50
|
+
from nautobot.virtualization.models import Cluster
|
|
49
51
|
|
|
50
52
|
logger = logging.getLogger(__name__)
|
|
51
53
|
|
|
@@ -123,16 +125,24 @@ class ObjectDetailContent:
|
|
|
123
125
|
class Component:
|
|
124
126
|
"""Common base class for renderable components (tabs, panels, etc.)."""
|
|
125
127
|
|
|
126
|
-
def __init__(
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
*,
|
|
131
|
+
weight,
|
|
132
|
+
required_permissions=None,
|
|
133
|
+
):
|
|
127
134
|
"""Initialize common Component properties.
|
|
128
135
|
|
|
129
136
|
Args:
|
|
130
137
|
weight (int): A relative weighting of this Component relative to its peers. Typically lower weights will be
|
|
131
138
|
rendered "first", usually towards the top left of the page.
|
|
139
|
+
required_permissions (list, optional): Permissions such as `["dcim.add_consoleport"]`.
|
|
140
|
+
The component will only be rendered if the user has these permissions.
|
|
132
141
|
"""
|
|
133
142
|
self.weight = weight
|
|
143
|
+
self.required_permissions = required_permissions or []
|
|
134
144
|
|
|
135
|
-
def should_render(self, context:
|
|
145
|
+
def should_render(self, context: Context):
|
|
136
146
|
"""
|
|
137
147
|
Check whether this component should be rendered at all.
|
|
138
148
|
|
|
@@ -140,9 +150,13 @@ class Component:
|
|
|
140
150
|
In general most Components may also return an empty string when actually rendered, which is typically also a
|
|
141
151
|
means to specify that they do not need to be rendered, but may be more expensive to derive.
|
|
142
152
|
|
|
153
|
+
The default implementation here checks for `self.required_permissions` if any.
|
|
154
|
+
|
|
143
155
|
Returns:
|
|
144
156
|
(bool): `True` (default) if this component should be rendered.
|
|
145
157
|
"""
|
|
158
|
+
if self.required_permissions:
|
|
159
|
+
return context["request"].user.has_perms(self.required_permissions)
|
|
146
160
|
return True
|
|
147
161
|
|
|
148
162
|
def render(self, context: Context):
|
|
@@ -178,12 +192,12 @@ class Button(Component):
|
|
|
178
192
|
link_name=None,
|
|
179
193
|
icon=None,
|
|
180
194
|
template_path="components/button/default.html",
|
|
181
|
-
required_permissions=None,
|
|
182
195
|
javascript_template_path=None,
|
|
183
196
|
attributes=None,
|
|
184
197
|
size=None,
|
|
185
198
|
link_includes_pk=True,
|
|
186
199
|
context_object_key=None,
|
|
200
|
+
render_on_tab_id="main",
|
|
187
201
|
**kwargs,
|
|
188
202
|
):
|
|
189
203
|
"""
|
|
@@ -199,30 +213,25 @@ class Button(Component):
|
|
|
199
213
|
context_object_key (str, optional): The key in the render context that will contain the linked object.
|
|
200
214
|
icon (str, optional): Material Design Icons icon, to include on the button, for example `"mdi-plus-bold"`.
|
|
201
215
|
template_path (str): Template to render for this button.
|
|
202
|
-
required_permissions (list, optional): Permissions such as `["dcim.add_consoleport"]`.
|
|
203
|
-
The button will only be rendered if the user has these permissions.
|
|
204
216
|
javascript_template_path (str, optional): JavaScript template to render and include with this button.
|
|
205
217
|
Does not need to include the wrapping `<script>...</script>` tags as those will be added automatically.
|
|
206
218
|
attributes (dict, optional): Additional HTML attributes and their values to attach to the button.
|
|
207
219
|
size (str, optional): The size of the button (e.g. `xs` or `sm`), used to apply a Bootstrap-style sizing.
|
|
220
|
+
render_on_tab_id (str, optional): The (only) tab that this button should appear on.
|
|
208
221
|
"""
|
|
209
222
|
self.label = label
|
|
210
223
|
self.color = color
|
|
211
224
|
self.link_name = link_name
|
|
212
225
|
self.icon = icon
|
|
213
226
|
self.template_path = template_path
|
|
214
|
-
self.required_permissions = required_permissions or []
|
|
215
227
|
self.javascript_template_path = javascript_template_path
|
|
216
228
|
self.attributes = attributes
|
|
217
229
|
self.size = size
|
|
218
230
|
self.link_includes_pk = link_includes_pk
|
|
219
231
|
self.context_object_key = context_object_key
|
|
232
|
+
self.render_on_tab_id = render_on_tab_id
|
|
220
233
|
super().__init__(**kwargs)
|
|
221
234
|
|
|
222
|
-
def should_render(self, context: Context):
|
|
223
|
-
"""Render if and only if the requesting user has appropriate permissions (if any)."""
|
|
224
|
-
return context["request"].user.has_perms(self.required_permissions)
|
|
225
|
-
|
|
226
235
|
def get_link(self, context: Context):
|
|
227
236
|
"""
|
|
228
237
|
Get the hyperlink URL (if any) for this button.
|
|
@@ -248,6 +257,11 @@ class Button(Component):
|
|
|
248
257
|
"size": self.size,
|
|
249
258
|
}
|
|
250
259
|
|
|
260
|
+
def should_render(self, context: Context):
|
|
261
|
+
if not super().should_render(context):
|
|
262
|
+
return False
|
|
263
|
+
return context.get("active_tab", "main") == self.render_on_tab_id
|
|
264
|
+
|
|
251
265
|
def render(self, context: Context):
|
|
252
266
|
"""Render this button to HTML, possibly including any associated JavaScript."""
|
|
253
267
|
if not self.should_render(context):
|
|
@@ -399,9 +413,18 @@ class Tab(Component):
|
|
|
399
413
|
"""
|
|
400
414
|
return self.label
|
|
401
415
|
|
|
416
|
+
def should_render_content(self, context: Context):
|
|
417
|
+
"""
|
|
418
|
+
Only render a main-view Tab if the active request is for the main object view rather than a separate action.
|
|
419
|
+
"""
|
|
420
|
+
request = context["request"]
|
|
421
|
+
obj = get_obj_from_context(context)
|
|
422
|
+
return request.path == obj.get_absolute_url()
|
|
423
|
+
|
|
402
424
|
def render(self, context: Context):
|
|
403
425
|
"""Render the tab's contents (layout and panels) to HTML."""
|
|
404
|
-
|
|
426
|
+
# Check should_render_content first as it's generally a cheaper calculation than should_render checking perms
|
|
427
|
+
if not self.should_render_content(context) or not self.should_render(context):
|
|
405
428
|
return ""
|
|
406
429
|
|
|
407
430
|
with context.update(
|
|
@@ -427,6 +450,7 @@ class DistinctViewTab(Tab):
|
|
|
427
450
|
url_name (str): The name of the URL pattern to link to, which will be reversed to generate the URL.
|
|
428
451
|
label_wrapper_template_path (str, optional): Template path to render the tab label to HTML.
|
|
429
452
|
related_object_attribute (str, optional): The name of the related object attribute to count for the tab label.
|
|
453
|
+
hide_if_empty (bool, optional): Do not render this tab if the related_object_attribute is an empty queryset.
|
|
430
454
|
"""
|
|
431
455
|
|
|
432
456
|
def __init__(
|
|
@@ -435,39 +459,62 @@ class DistinctViewTab(Tab):
|
|
|
435
459
|
url_name,
|
|
436
460
|
label_wrapper_template_path="components/tab/label_wrapper_distinct_view.html",
|
|
437
461
|
related_object_attribute="",
|
|
462
|
+
hide_if_empty=False,
|
|
438
463
|
**kwargs,
|
|
439
464
|
):
|
|
440
465
|
self.url_name = url_name
|
|
441
466
|
self.related_object_attribute = related_object_attribute
|
|
467
|
+
self.hide_if_empty = hide_if_empty
|
|
442
468
|
super().__init__(label_wrapper_template_path=label_wrapper_template_path, **kwargs)
|
|
443
469
|
|
|
444
470
|
def get_extra_context(self, context: Context):
|
|
445
471
|
return {"url": reverse(self.url_name, kwargs={"pk": get_obj_from_context(context).pk})}
|
|
446
472
|
|
|
447
|
-
def
|
|
473
|
+
def should_render(self, context: Context):
|
|
474
|
+
if not super().should_render(context):
|
|
475
|
+
return False
|
|
476
|
+
|
|
477
|
+
self.related_object_count = None
|
|
448
478
|
if not self.related_object_attribute:
|
|
449
|
-
return
|
|
479
|
+
return True
|
|
450
480
|
|
|
451
481
|
obj = get_obj_from_context(context)
|
|
452
482
|
if not hasattr(obj, self.related_object_attribute):
|
|
453
483
|
logger.warning(
|
|
454
484
|
f"{obj} does not have a related attribute {self.related_object_attribute} to count for tab label."
|
|
455
485
|
)
|
|
456
|
-
return
|
|
486
|
+
return True
|
|
457
487
|
|
|
458
488
|
try:
|
|
459
|
-
|
|
460
|
-
return format_html(
|
|
461
|
-
"{} {}",
|
|
462
|
-
self.label,
|
|
463
|
-
render_to_string("utilities/templatetags/badge.html", badge(related_obj_count, True)),
|
|
464
|
-
)
|
|
489
|
+
self.related_object_count = getattr(obj, self.related_object_attribute).count()
|
|
465
490
|
except AttributeError:
|
|
466
|
-
|
|
491
|
+
# Not a warning log, as there are cases where this is expected.
|
|
492
|
+
logger.debug(
|
|
467
493
|
f"{obj}'s attribute {self.related_object_attribute} is not a related manager to count for tab label."
|
|
468
494
|
)
|
|
495
|
+
|
|
496
|
+
if self.hide_if_empty and not self.related_object_count:
|
|
497
|
+
return False
|
|
498
|
+
return True
|
|
499
|
+
|
|
500
|
+
def should_render_content(self, context: Context):
|
|
501
|
+
"""
|
|
502
|
+
A DistinctViewTab should only render its content if the view in question is active.
|
|
503
|
+
"""
|
|
504
|
+
with context.update(self.get_extra_context(context)):
|
|
505
|
+
request = context["request"]
|
|
506
|
+
return request.path == context["url"]
|
|
507
|
+
|
|
508
|
+
def render_label(self, context: Context):
|
|
509
|
+
if not self.related_object_attribute or not self.related_object_count:
|
|
469
510
|
return super().render_label(context)
|
|
470
511
|
|
|
512
|
+
return format_html(
|
|
513
|
+
"{} {}",
|
|
514
|
+
self.label,
|
|
515
|
+
render_to_string("utilities/templatetags/badge.html", badge(self.related_object_count, True)),
|
|
516
|
+
)
|
|
517
|
+
|
|
471
518
|
|
|
472
519
|
class Panel(Component):
|
|
473
520
|
"""Base class for defining an individual display panel within a Layout within a Tab."""
|
|
@@ -607,7 +654,7 @@ class DataTablePanel(Panel):
|
|
|
607
654
|
**kwargs,
|
|
608
655
|
):
|
|
609
656
|
"""
|
|
610
|
-
Instantiate a
|
|
657
|
+
Instantiate a DataTablePanel.
|
|
611
658
|
|
|
612
659
|
Args:
|
|
613
660
|
context_data_key (str): The key in the render context that stores the data used to populate the table.
|
|
@@ -684,6 +731,7 @@ class ObjectsTablePanel(Panel):
|
|
|
684
731
|
table_class=None,
|
|
685
732
|
table_filter=None,
|
|
686
733
|
table_attribute=None,
|
|
734
|
+
distinct=False,
|
|
687
735
|
select_related_fields=None,
|
|
688
736
|
prefetch_related_fields=None,
|
|
689
737
|
order_by_fields=None,
|
|
@@ -726,6 +774,7 @@ class ObjectsTablePanel(Panel):
|
|
|
726
774
|
table_attribute (str, optional): The attribute of the detail view instance that contains the queryset to
|
|
727
775
|
initialize the table class. e.g. `dynamic_groups`.
|
|
728
776
|
Mutually exclusive with `table_filter`.
|
|
777
|
+
distinct (bool, optional): If True, apply `.distinct()` to the table queryset.
|
|
729
778
|
select_related_fields (list, optional): list of fields to pass to table queryset's `select_related` method.
|
|
730
779
|
prefetch_related_fields (list, optional): list of fields to pass to table queryset's `prefetch_related`
|
|
731
780
|
method.
|
|
@@ -761,6 +810,7 @@ class ObjectsTablePanel(Panel):
|
|
|
761
810
|
table_class,
|
|
762
811
|
table_filter,
|
|
763
812
|
table_attribute,
|
|
813
|
+
distinct,
|
|
764
814
|
select_related_fields,
|
|
765
815
|
prefetch_related_fields,
|
|
766
816
|
order_by_fields,
|
|
@@ -769,8 +819,8 @@ class ObjectsTablePanel(Panel):
|
|
|
769
819
|
):
|
|
770
820
|
raise ValueError(
|
|
771
821
|
"context_table_key cannot be combined with any of the args that are used to dynamically construct the "
|
|
772
|
-
"table (table_class, table_filter, table_attribute,
|
|
773
|
-
"order_by_fields, hide_hierarchy_ui)."
|
|
822
|
+
"table (table_class, table_filter, table_attribute, distinct, select_related_fields, "
|
|
823
|
+
"prefetch_related_fields, order_by_fields, hide_hierarchy_ui)."
|
|
774
824
|
)
|
|
775
825
|
self.context_table_key = context_table_key
|
|
776
826
|
self.table_class = table_class
|
|
@@ -782,6 +832,7 @@ class ObjectsTablePanel(Panel):
|
|
|
782
832
|
raise ValueError("You must provide a `related_field_name` when specifying `table_attribute`")
|
|
783
833
|
self.table_filter = table_filter
|
|
784
834
|
self.table_attribute = table_attribute
|
|
835
|
+
self.distinct = distinct
|
|
785
836
|
self.select_related_fields = select_related_fields
|
|
786
837
|
self.prefetch_related_fields = prefetch_related_fields
|
|
787
838
|
self.order_by_fields = order_by_fields
|
|
@@ -792,7 +843,7 @@ class ObjectsTablePanel(Panel):
|
|
|
792
843
|
self.include_columns = include_columns
|
|
793
844
|
self.exclude_columns = exclude_columns
|
|
794
845
|
self.add_button_route = add_button_route
|
|
795
|
-
self.add_permissions = add_permissions
|
|
846
|
+
self.add_permissions = add_permissions or []
|
|
796
847
|
self.hide_hierarchy_ui = hide_hierarchy_ui
|
|
797
848
|
self.related_field_name = related_field_name
|
|
798
849
|
self.enable_bulk_actions = enable_bulk_actions
|
|
@@ -823,21 +874,26 @@ class ObjectsTablePanel(Panel):
|
|
|
823
874
|
if self.tab_id:
|
|
824
875
|
return_url += f"?tab={self.tab_id}"
|
|
825
876
|
|
|
826
|
-
if self.add_button_route
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
add_route = reverse(get_route_for_model(body_content_table_model, "add"))
|
|
833
|
-
body_content_table_add_url = f"{add_route}?{related_field_name}={obj.pk}&return_url={return_url}"
|
|
834
|
-
except NoReverseMatch:
|
|
835
|
-
logger.warning("add route for `body_content_table_model` not found")
|
|
877
|
+
if self.add_button_route is not None:
|
|
878
|
+
add_permissions = self.add_permissions
|
|
879
|
+
if not add_permissions:
|
|
880
|
+
body_content_table_class = self.table_class or context[self.context_table_key].__class__
|
|
881
|
+
body_content_table_model = body_content_table_class.Meta.model
|
|
882
|
+
add_permissions = [get_permission_for_model(body_content_table_model, "add")]
|
|
836
883
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
884
|
+
if self.add_button_route == "default":
|
|
885
|
+
if request.user.has_perms(add_permissions):
|
|
886
|
+
try:
|
|
887
|
+
add_route = reverse(get_route_for_model(body_content_table_model, "add"))
|
|
888
|
+
body_content_table_add_url = (
|
|
889
|
+
f"{add_route}?{related_field_name}={obj.pk}&return_url={return_url}"
|
|
890
|
+
)
|
|
891
|
+
except NoReverseMatch:
|
|
892
|
+
logger.warning("add route for `body_content_table_model` not found")
|
|
893
|
+
else:
|
|
894
|
+
if request.user.has_perms(add_permissions):
|
|
895
|
+
add_route = reverse(self.add_button_route)
|
|
896
|
+
body_content_table_add_url = f"{add_route}?{related_field_name}={obj.pk}&return_url={return_url}"
|
|
841
897
|
|
|
842
898
|
return body_content_table_add_url
|
|
843
899
|
|
|
@@ -880,7 +936,8 @@ class ObjectsTablePanel(Panel):
|
|
|
880
936
|
)
|
|
881
937
|
if self.order_by_fields:
|
|
882
938
|
body_content_table_queryset = body_content_table_queryset.order_by(*self.order_by_fields)
|
|
883
|
-
|
|
939
|
+
if self.distinct:
|
|
940
|
+
body_content_table_queryset = body_content_table_queryset.distinct()
|
|
884
941
|
body_content_table = body_content_table_class(
|
|
885
942
|
body_content_table_queryset, hide_hierarchy_ui=self.hide_hierarchy_ui, user=request.user
|
|
886
943
|
)
|
|
@@ -1004,6 +1061,8 @@ class KeyValueTablePanel(Panel):
|
|
|
1004
1061
|
super().__init__(body_wrapper_template_path=body_wrapper_template_path, **kwargs)
|
|
1005
1062
|
|
|
1006
1063
|
def should_render(self, context: Context):
|
|
1064
|
+
if not super().should_render(context):
|
|
1065
|
+
return False
|
|
1007
1066
|
return bool(self.get_data(context))
|
|
1008
1067
|
|
|
1009
1068
|
def get_data(self, context: Context):
|
|
@@ -1093,6 +1152,10 @@ class KeyValueTablePanel(Panel):
|
|
|
1093
1152
|
elif isinstance(value, models.Model):
|
|
1094
1153
|
if hasattr(value, "color"):
|
|
1095
1154
|
display = hyperlinked_object_with_color(value)
|
|
1155
|
+
elif isinstance(value, Cluster) and value.cluster_group is not None:
|
|
1156
|
+
display = format_html("{} / {}", hyperlinked_object(value.cluster_group), hyperlinked_object(value))
|
|
1157
|
+
elif isinstance(value, Rack) and value.rack_group is not None:
|
|
1158
|
+
display = format_html("{} / {}", hyperlinked_object(value.rack_group), hyperlinked_object(value))
|
|
1096
1159
|
elif isinstance(value, Tenant) and value.tenant_group is not None:
|
|
1097
1160
|
display = format_html("{} / {}", hyperlinked_object(value.tenant_group), hyperlinked_object(value))
|
|
1098
1161
|
# TODO: render location hierarchy for Location objects
|
|
@@ -1317,6 +1380,8 @@ class ObjectFieldsPanel(KeyValueTablePanel):
|
|
|
1317
1380
|
for token in field_name.split(LOOKUP_SEP):
|
|
1318
1381
|
try:
|
|
1319
1382
|
field_value = getattr(field_value, token)
|
|
1383
|
+
if field_value is None:
|
|
1384
|
+
break
|
|
1320
1385
|
except ObjectDoesNotExist:
|
|
1321
1386
|
field_value = None
|
|
1322
1387
|
break
|
|
@@ -1610,7 +1675,7 @@ class _ObjectCustomFieldsPanel(GroupedKeyValueTablePanel):
|
|
|
1610
1675
|
if not hasattr(obj, "get_custom_field_groupings"):
|
|
1611
1676
|
return False
|
|
1612
1677
|
self.custom_field_data = obj.get_custom_field_groupings(advanced_ui=self.advanced_ui)
|
|
1613
|
-
return bool(self.custom_field_data)
|
|
1678
|
+
return bool(self.custom_field_data) and super().should_render(context)
|
|
1614
1679
|
|
|
1615
1680
|
def get_data(self, context: Context):
|
|
1616
1681
|
"""Remap the response from `get_custom_field_groupings()` to a nested dict as expected by the parent class."""
|
|
@@ -1686,7 +1751,7 @@ class _ObjectComputedFieldsPanel(GroupedKeyValueTablePanel):
|
|
|
1686
1751
|
if not hasattr(obj, "get_computed_fields_grouping"):
|
|
1687
1752
|
return False
|
|
1688
1753
|
self.computed_fields_data = obj.get_computed_fields_grouping(advanced_ui=self.advanced_ui)
|
|
1689
|
-
return bool(self.computed_fields_data)
|
|
1754
|
+
return bool(self.computed_fields_data) and super().should_render(context)
|
|
1690
1755
|
|
|
1691
1756
|
def get_data(self, context: Context):
|
|
1692
1757
|
"""Remap `get_computed_fields_grouping()` to the nested dict format expected by the base class."""
|
|
@@ -1732,7 +1797,7 @@ class _ObjectRelationshipsPanel(KeyValueTablePanel):
|
|
|
1732
1797
|
self.relationships_data["source"]
|
|
1733
1798
|
or self.relationships_data["destination"]
|
|
1734
1799
|
or self.relationships_data["peer"]
|
|
1735
|
-
)
|
|
1800
|
+
) and super().should_render(context)
|
|
1736
1801
|
|
|
1737
1802
|
def get_data(self, context: Context):
|
|
1738
1803
|
"""Remap `get_relationships_with_related_objects()` to the flat dict format expected by the base class."""
|
|
@@ -1783,6 +1848,8 @@ class _ObjectTagsPanel(Panel):
|
|
|
1783
1848
|
)
|
|
1784
1849
|
|
|
1785
1850
|
def should_render(self, context: Context):
|
|
1851
|
+
if not super().should_render(context):
|
|
1852
|
+
return False
|
|
1786
1853
|
return hasattr(get_obj_from_context(context), "tags")
|
|
1787
1854
|
|
|
1788
1855
|
def get_extra_context(self, context: Context):
|
|
@@ -1814,6 +1881,8 @@ class _ObjectCommentPanel(ObjectTextPanel):
|
|
|
1814
1881
|
)
|
|
1815
1882
|
|
|
1816
1883
|
def should_render(self, context: Context):
|
|
1884
|
+
if not super().should_render(context):
|
|
1885
|
+
return False
|
|
1817
1886
|
return hasattr(get_obj_from_context(context), "comments")
|
|
1818
1887
|
|
|
1819
1888
|
|
|
@@ -1947,6 +2016,8 @@ class _ObjectDetailContactsTab(Tab):
|
|
|
1947
2016
|
super().__init__(tab_id=tab_id, label=label, weight=weight, panels=panels, **kwargs)
|
|
1948
2017
|
|
|
1949
2018
|
def should_render(self, context: Context):
|
|
2019
|
+
if not super().should_render(context):
|
|
2020
|
+
return False
|
|
1950
2021
|
return getattr(get_obj_from_context(context), "is_contact_associable_model", False)
|
|
1951
2022
|
|
|
1952
2023
|
def render_label(self, context: Context):
|
|
@@ -1971,6 +2042,7 @@ class _ObjectDetailGroupsTab(Tab):
|
|
|
1971
2042
|
label="Dynamic Groups",
|
|
1972
2043
|
weight=Tab.WEIGHT_GROUPS_TAB,
|
|
1973
2044
|
panels=None,
|
|
2045
|
+
required_permissions=("extras.view_dynamic_group",),
|
|
1974
2046
|
**kwargs,
|
|
1975
2047
|
):
|
|
1976
2048
|
if panels is None:
|
|
@@ -1984,15 +2056,20 @@ class _ObjectDetailGroupsTab(Tab):
|
|
|
1984
2056
|
related_field_name="member_id",
|
|
1985
2057
|
),
|
|
1986
2058
|
)
|
|
1987
|
-
super().__init__(
|
|
2059
|
+
super().__init__(
|
|
2060
|
+
tab_id=tab_id,
|
|
2061
|
+
label=label,
|
|
2062
|
+
weight=weight,
|
|
2063
|
+
panels=panels,
|
|
2064
|
+
required_permissions=required_permissions,
|
|
2065
|
+
**kwargs,
|
|
2066
|
+
)
|
|
1988
2067
|
|
|
1989
2068
|
def should_render(self, context: Context):
|
|
2069
|
+
if not super().should_render(context):
|
|
2070
|
+
return False
|
|
1990
2071
|
obj = get_obj_from_context(context)
|
|
1991
|
-
return (
|
|
1992
|
-
getattr(obj, "is_dynamic_group_associable_model", False)
|
|
1993
|
-
and context["request"].user.has_perm("extras.view_dynamicgroup")
|
|
1994
|
-
and obj.dynamic_groups.exists()
|
|
1995
|
-
)
|
|
2072
|
+
return getattr(obj, "is_dynamic_group_associable_model", False) and obj.dynamic_groups.exists()
|
|
1996
2073
|
|
|
1997
2074
|
def render_label(self, context: Context):
|
|
1998
2075
|
return format_html(
|
|
@@ -2015,6 +2092,7 @@ class _ObjectDetailMetadataTab(Tab):
|
|
|
2015
2092
|
label="Object Metadata",
|
|
2016
2093
|
weight=Tab.WEIGHT_METADATA_TAB,
|
|
2017
2094
|
panels=None,
|
|
2095
|
+
required_permissions=("extras.view_objectmetadata",),
|
|
2018
2096
|
**kwargs,
|
|
2019
2097
|
):
|
|
2020
2098
|
if panels is None:
|
|
@@ -2030,15 +2108,20 @@ class _ObjectDetailMetadataTab(Tab):
|
|
|
2030
2108
|
header_extra_content_template_path=None,
|
|
2031
2109
|
),
|
|
2032
2110
|
)
|
|
2033
|
-
super().__init__(
|
|
2111
|
+
super().__init__(
|
|
2112
|
+
tab_id=tab_id,
|
|
2113
|
+
label=label,
|
|
2114
|
+
weight=weight,
|
|
2115
|
+
panels=panels,
|
|
2116
|
+
required_permissions=required_permissions,
|
|
2117
|
+
**kwargs,
|
|
2118
|
+
)
|
|
2034
2119
|
|
|
2035
2120
|
def should_render(self, context: Context):
|
|
2121
|
+
if not super().should_render(context):
|
|
2122
|
+
return False
|
|
2036
2123
|
obj = get_obj_from_context(context)
|
|
2037
|
-
return (
|
|
2038
|
-
getattr(obj, "is_metadata_associable_model", False)
|
|
2039
|
-
and context["request"].user.has_perm("extras.view_objectmetadata")
|
|
2040
|
-
and obj.associated_object_metadata.exists()
|
|
2041
|
-
)
|
|
2124
|
+
return getattr(obj, "is_metadata_associable_model", False) and obj.associated_object_metadata.exists()
|
|
2042
2125
|
|
|
2043
2126
|
def render_label(self, context: Context):
|
|
2044
2127
|
return format_html(
|
nautobot/core/ui/titles.py
CHANGED
|
@@ -15,6 +15,7 @@ DEFAULT_TITLES: dict[str, str] = {
|
|
|
15
15
|
"bulk_rename": "Renaming {{ selected_objects|length }} {{ verbose_name_plural|bettertitle }} on {{ parent_name }}",
|
|
16
16
|
"bulk_update": "Editing {{ objs_count }} {{ verbose_name_plural|bettertitle }}",
|
|
17
17
|
"changelog": "{{ object.display|default:object }} - Change Log",
|
|
18
|
+
"config_context": "{{ object.display|default:object }} - Config Context",
|
|
18
19
|
"notes": "{{ object.display|default:object }} - Notes",
|
|
19
20
|
"approve": "Approve {{ verbose_name|bettertitle }}?",
|
|
20
21
|
"deny": "Deny {{ verbose_name|bettertitle }}?",
|
nautobot/core/utils/requests.py
CHANGED
|
@@ -156,7 +156,7 @@ def normalize_querydict(querydict, form_class=None, filterset=None):
|
|
|
156
156
|
does not inherently preserve multiple values as lists.
|
|
157
157
|
|
|
158
158
|
Args:
|
|
159
|
-
querydict (QueryDict): The QueryDict to be normalized.
|
|
159
|
+
querydict (QueryDict): The QueryDict or dictionary as produced by `convert_querydict_to_dict` to be normalized.
|
|
160
160
|
form_class (forms.Form, optional): A form class to identify fields that should be treated as
|
|
161
161
|
lists (e.g., `MultipleChoiceField` or `ModelMultipleChoiceField`).
|
|
162
162
|
filterset (django_filters.FilterSet, optional): A FilterSet instance to identify filters that
|
|
@@ -171,7 +171,13 @@ def normalize_querydict(querydict, form_class=None, filterset=None):
|
|
|
171
171
|
result = {}
|
|
172
172
|
|
|
173
173
|
if querydict:
|
|
174
|
-
|
|
174
|
+
# check if true QueryDict or standard dict in format of querydict, e.g. from `convert_querydict_to_dict`
|
|
175
|
+
if hasattr(querydict, "lists"):
|
|
176
|
+
items = querydict.lists()
|
|
177
|
+
else:
|
|
178
|
+
items = querydict.items()
|
|
179
|
+
|
|
180
|
+
for key, value_list in items:
|
|
175
181
|
if len(value_list) > 1:
|
|
176
182
|
# More than one value in the querydict for this key, so keep it as a list
|
|
177
183
|
# TODO: we could check here and de-listify value_list if the form_class field is a single-value one?
|
|
@@ -198,3 +204,22 @@ def add_nautobot_version_query_param_to_url(url):
|
|
|
198
204
|
params["version"] = settings.VERSION
|
|
199
205
|
updated_query = urlencode(params, doseq=True)
|
|
200
206
|
return parsed_url._replace(query=updated_query).geturl()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def convert_querydict_to_dict(request_querydict):
|
|
210
|
+
"""
|
|
211
|
+
Convert QueryDict to standard json serializable dictionary.
|
|
212
|
+
|
|
213
|
+
This is useful when you want to serialize a QueryDict to JSON format such as
|
|
214
|
+
when sending to a Job form or sending it over an API. This is not the same as
|
|
215
|
+
`normalize_querydict` which preserves single values as singletons and multi-values
|
|
216
|
+
as lists. This function preserves all values as lists.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
request_querydict (QueryDict): QueryDict to convert.
|
|
220
|
+
|
|
221
|
+
Examples:
|
|
222
|
+
>>> convert_querydict_to_dict(QueryDict('foo=1&bar=2&bar=3&baz='))
|
|
223
|
+
>>> {'foo': ['1'], 'bar': ['2', '3'], 'baz': ['']}
|
|
224
|
+
"""
|
|
225
|
+
return {key: value for key, value in request_querydict.lists()} # pylint: disable=unnecessary-comprehension
|