nautobot 2.3.16__py3-none-any.whl → 2.4.0b1__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/__init__.py +15 -0
- nautobot/apps/api.py +0 -2
- nautobot/apps/config.py +32 -3
- nautobot/apps/events.py +19 -0
- nautobot/apps/exceptions.py +0 -2
- nautobot/apps/ui.py +44 -9
- nautobot/apps/utils.py +0 -8
- nautobot/apps/views.py +2 -0
- nautobot/circuits/navigation.py +0 -57
- nautobot/circuits/tables.py +1 -2
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
- nautobot/circuits/tests/integration/test_relationships.py +33 -24
- nautobot/circuits/tests/test_filters.py +4 -8
- nautobot/circuits/views.py +143 -26
- nautobot/cloud/factory.py +4 -1
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/tests/test_filters.py +5 -4
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/metadata.py +28 -256
- nautobot/core/api/pagination.py +3 -2
- nautobot/core/api/renderers.py +3 -0
- nautobot/core/api/serializers.py +24 -244
- nautobot/core/api/urls.py +3 -4
- nautobot/core/api/utils.py +0 -62
- nautobot/core/api/views.py +48 -158
- nautobot/core/apps/__init__.py +22 -578
- nautobot/core/celery/__init__.py +13 -0
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +48 -3
- nautobot/core/cli/__init__.py +8 -0
- nautobot/core/constants.py +7 -0
- nautobot/core/events/__init__.py +116 -0
- nautobot/core/events/base.py +27 -0
- nautobot/core/events/exceptions.py +10 -0
- nautobot/core/events/redis_broker.py +48 -0
- nautobot/core/events/syslog_broker.py +19 -0
- nautobot/core/exceptions.py +0 -6
- nautobot/core/filters.py +16 -21
- nautobot/core/fixtures/user-data.json +59 -0
- nautobot/core/forms/fields.py +53 -8
- nautobot/core/forms/utils.py +2 -1
- nautobot/core/graphql/schema.py +3 -1
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +4 -4
- nautobot/core/jobs/cleanup.py +13 -49
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +21 -0
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/middleware.py +16 -0
- nautobot/core/models/__init__.py +1 -1
- nautobot/core/models/fields.py +11 -7
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +3 -6
- nautobot/core/settings.py +44 -7
- nautobot/core/settings.yaml +86 -8
- nautobot/core/tables.py +15 -65
- nautobot/core/tasks.py +1 -1
- nautobot/core/templates/components/button/default.html +7 -0
- nautobot/core/templates/components/button/dropdown.html +20 -0
- nautobot/core/templates/components/layout/one_over_two.html +19 -0
- nautobot/core/templates/components/layout/two_over_one.html +19 -0
- nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
- nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
- nautobot/core/templates/components/panel/body_content_tags.html +6 -0
- nautobot/core/templates/components/panel/body_content_text.html +12 -0
- nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
- nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
- nautobot/core/templates/components/panel/footer_content_table.html +14 -0
- nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
- nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
- nautobot/core/templates/components/panel/panel.html +16 -0
- nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
- nautobot/core/templates/components/tab/content_wrapper.html +3 -0
- nautobot/core/templates/components/tab/label_wrapper.html +5 -0
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
- nautobot/core/templates/generic/object_retrieve.html +28 -17
- nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/custom_fields/panel.html +2 -2
- nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/media.html +0 -3
- nautobot/core/templates/inc/nav_menu.html +1 -1
- nautobot/core/templates/inc/relationships_panel.html +1 -1
- nautobot/core/templates/nautobot_config.py.j2 +3 -3
- nautobot/core/templates/panel_table.html +12 -0
- nautobot/core/templates/search.html +0 -7
- nautobot/core/templates/utilities/render_jinja2.html +117 -0
- nautobot/core/templatetags/helpers.py +101 -12
- nautobot/core/templatetags/ui_framework.py +40 -0
- nautobot/core/testing/api.py +23 -128
- nautobot/core/testing/context.py +18 -0
- nautobot/core/testing/filters.py +41 -58
- nautobot/core/testing/mixins.py +2 -7
- nautobot/core/testing/views.py +25 -123
- nautobot/core/tests/integration/test_app_home.py +1 -0
- nautobot/core/tests/integration/test_app_navbar.py +1 -0
- nautobot/core/tests/integration/test_filters.py +2 -0
- nautobot/core/tests/integration/test_home.py +1 -0
- nautobot/core/tests/integration/test_navbar.py +1 -0
- nautobot/core/tests/integration/test_view_authentication.py +1 -2
- nautobot/core/tests/nautobot_config.py +198 -0
- nautobot/core/tests/runner.py +3 -3
- nautobot/core/tests/test_api.py +82 -201
- nautobot/core/tests/test_csv.py +3 -25
- nautobot/core/tests/test_events.py +214 -0
- nautobot/core/tests/test_jinja_filters.py +1 -0
- nautobot/core/tests/test_jobs.py +84 -13
- nautobot/core/tests/test_navigations.py +7 -241
- nautobot/core/tests/test_templatetags_helpers.py +16 -0
- nautobot/core/tests/test_ui.py +150 -0
- nautobot/core/tests/test_utils.py +0 -25
- nautobot/core/tests/test_views.py +123 -31
- nautobot/core/ui/__init__.py +0 -0
- nautobot/core/ui/base.py +11 -0
- nautobot/core/ui/choices.py +44 -0
- nautobot/core/ui/homepage.py +167 -0
- nautobot/core/ui/nav.py +279 -0
- nautobot/core/ui/object_detail.py +1841 -0
- nautobot/core/ui/utils.py +36 -0
- nautobot/core/urls.py +4 -9
- nautobot/core/utils/config.py +30 -3
- nautobot/core/utils/lookup.py +20 -13
- nautobot/core/views/__init__.py +6 -1
- nautobot/core/views/generic.py +47 -52
- nautobot/core/views/mixins.py +15 -25
- nautobot/core/views/paginator.py +8 -5
- nautobot/core/views/renderers.py +3 -3
- nautobot/core/views/utils.py +11 -0
- nautobot/core/wsgi.py +3 -3
- nautobot/dcim/api/serializers.py +80 -179
- nautobot/dcim/api/urls.py +5 -0
- nautobot/dcim/api/views.py +17 -4
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/choices.py +28 -0
- nautobot/dcim/factory.py +58 -0
- nautobot/dcim/filters/__init__.py +197 -24
- nautobot/dcim/forms.py +203 -12
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
- nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
- nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
- nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
- nautobot/dcim/models/__init__.py +4 -0
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +20 -22
- nautobot/dcim/models/devices.py +173 -4
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +5 -6
- nautobot/dcim/models/racks.py +6 -6
- nautobot/dcim/navigation.py +25 -224
- nautobot/dcim/signals.py +44 -0
- nautobot/dcim/tables/__init__.py +5 -3
- nautobot/dcim/tables/devices.py +96 -2
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/templates/dcim/controller/base.html +10 -0
- nautobot/dcim/templates/dcim/controller_create.html +1 -0
- nautobot/dcim/templates/dcim/controller_retrieve.html +5 -1
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +66 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +46 -0
- nautobot/dcim/templates/dcim/device/base.html +6 -42
- nautobot/dcim/templates/dcim/device/wireless.html +73 -0
- nautobot/dcim/templates/dcim/device.html +3 -1
- nautobot/dcim/templates/dcim/interface.html +1 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/locationtype.html +0 -107
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +76 -0
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +34 -0
- nautobot/dcim/tests/test_api.py +172 -61
- nautobot/dcim/tests/test_filters.py +171 -109
- nautobot/dcim/tests/test_forms.py +2 -51
- nautobot/dcim/tests/test_graphql.py +0 -52
- nautobot/dcim/tests/test_models.py +126 -4
- nautobot/dcim/tests/test_signals.py +1 -0
- nautobot/dcim/tests/test_views.py +103 -11
- nautobot/dcim/urls.py +72 -27
- nautobot/dcim/utils.py +2 -2
- nautobot/dcim/views.py +369 -62
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +91 -75
- nautobot/extras/api/urls.py +4 -0
- nautobot/extras/api/views.py +78 -15
- nautobot/extras/choices.py +13 -0
- nautobot/extras/constants.py +0 -1
- nautobot/extras/context_managers.py +23 -6
- nautobot/extras/datasources/git.py +4 -1
- nautobot/extras/factory.py +27 -0
- nautobot/extras/filters/__init__.py +59 -0
- nautobot/extras/forms/forms.py +125 -30
- nautobot/extras/forms/mixins.py +3 -11
- nautobot/extras/graphql/types.py +25 -1
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +2 -1
- nautobot/extras/jobs.py +62 -26
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/runjob.py +7 -79
- nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
- nautobot/extras/management/utils.py +87 -0
- nautobot/extras/managers.py +1 -3
- nautobot/extras/migrations/0018_joblog_data_migration.py +9 -7
- nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
- nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
- nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
- nautobot/extras/models/__init__.py +4 -0
- nautobot/extras/models/change_logging.py +7 -3
- nautobot/extras/models/customfields.py +11 -12
- nautobot/extras/models/groups.py +9 -13
- nautobot/extras/models/jobs.py +218 -37
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/models/relationships.py +69 -1
- nautobot/extras/models/secrets.py +5 -0
- nautobot/extras/navigation.py +20 -262
- nautobot/extras/plugins/__init__.py +56 -32
- nautobot/extras/plugins/marketplace_manifest.yml +450 -0
- nautobot/extras/plugins/urls.py +1 -0
- nautobot/extras/plugins/views.py +48 -1
- nautobot/extras/signals.py +39 -1
- nautobot/extras/tables.py +40 -6
- nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
- nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
- nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
- nautobot/extras/templates/extras/job_detail.html +36 -6
- nautobot/extras/templates/extras/job_edit.html +5 -2
- nautobot/extras/templates/extras/job_list.html +2 -7
- nautobot/extras/templates/extras/jobqueue_retrieve.html +44 -0
- nautobot/extras/templates/extras/marketplace.html +278 -0
- nautobot/extras/templates/extras/plugins_list.html +35 -1
- nautobot/extras/templates/extras/plugins_tiles.html +79 -0
- nautobot/extras/templates/extras/role_retrieve.html +16 -0
- nautobot/extras/templates/extras/secret.html +0 -65
- nautobot/extras/templates/extras/secret_check.js +16 -0
- nautobot/extras/templates/extras/secret_create.html +114 -0
- nautobot/extras/templates/extras/secret_edit.html +1 -114
- nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
- nautobot/extras/templatetags/job_buttons.py +5 -4
- nautobot/extras/templatetags/plugins.py +69 -6
- nautobot/extras/test_jobs/api_test_job.py +1 -1
- nautobot/extras/test_jobs/atomic_transaction.py +2 -2
- nautobot/extras/test_jobs/dry_run.py +1 -1
- nautobot/extras/test_jobs/fail.py +5 -5
- nautobot/extras/test_jobs/file_output.py +1 -1
- nautobot/extras/test_jobs/file_upload_fail.py +1 -1
- nautobot/extras/test_jobs/file_upload_pass.py +1 -1
- nautobot/extras/test_jobs/ipaddress_vars.py +1 -3
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
- nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
- nautobot/extras/test_jobs/log_redaction.py +1 -1
- nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
- nautobot/extras/test_jobs/modify_db.py +1 -1
- nautobot/extras/test_jobs/object_var_optional.py +1 -1
- nautobot/extras/test_jobs/object_var_required.py +1 -1
- nautobot/extras/test_jobs/object_vars.py +1 -1
- nautobot/extras/test_jobs/pass.py +3 -3
- nautobot/extras/test_jobs/profiling.py +1 -1
- nautobot/extras/test_jobs/relative_import.py +3 -3
- nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
- nautobot/extras/test_jobs/task_queues.py +1 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +2 -0
- nautobot/extras/tests/test_api.py +157 -55
- nautobot/extras/tests/test_context_managers.py +4 -1
- nautobot/extras/tests/test_customfields.py +1 -1
- nautobot/extras/tests/test_datasources.py +1 -2
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +219 -535
- nautobot/extras/tests/test_forms.py +1 -20
- nautobot/extras/tests/test_job_variables.py +73 -152
- nautobot/extras/tests/test_jobs.py +43 -54
- nautobot/extras/tests/test_models.py +71 -16
- nautobot/extras/tests/test_relationships.py +5 -2
- nautobot/extras/tests/test_utils.py +23 -2
- nautobot/extras/tests/test_views.py +183 -43
- nautobot/extras/tests/test_webhooks.py +2 -1
- nautobot/extras/urls.py +2 -20
- nautobot/extras/utils.py +118 -4
- nautobot/extras/views.py +203 -92
- nautobot/extras/webhooks.py +5 -2
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +36 -137
- nautobot/ipam/api/views.py +93 -62
- nautobot/ipam/lookups.py +62 -101
- nautobot/ipam/models.py +11 -63
- nautobot/ipam/navigation.py +0 -90
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +6 -20
- nautobot/ipam/templates/ipam/routetarget.html +0 -28
- nautobot/ipam/templates/ipam/vrf.html +0 -47
- nautobot/ipam/tests/test_api.py +8 -419
- nautobot/ipam/tests/test_filters.py +39 -119
- nautobot/ipam/tests/test_forms.py +47 -51
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +0 -41
- nautobot/ipam/tests/test_querysets.py +1 -63
- nautobot/ipam/urls.py +3 -69
- nautobot/ipam/utils/__init__.py +0 -24
- nautobot/ipam/views.py +153 -198
- nautobot/project-static/css/base.css +38 -3
- nautobot/project-static/docs/404.html +421 -19
- nautobot/project-static/docs/apps/index.html +421 -19
- nautobot/project-static/docs/apps/nautobot-apps.html +421 -19
- nautobot/project-static/docs/assets/extra.css +5 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.83f73b43.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.83f73b43.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +421 -172
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +425 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +424 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9809 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +424 -63
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +457 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +425 -25
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +457 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +425 -215
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +430 -342
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5799 -1054
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +421 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +447 -176
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +460 -21
- nautobot/project-static/docs/development/apps/api/configuration-view.html +421 -19
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +421 -19
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +421 -19
- nautobot/project-static/docs/development/apps/api/models/global-search.html +421 -19
- nautobot/project-static/docs/development/apps/api/models/graphql.html +421 -19
- nautobot/project-static/docs/development/apps/api/models/index.html +421 -19
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +421 -19
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +424 -41
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +421 -19
- nautobot/project-static/docs/development/apps/api/prometheus.html +421 -19
- nautobot/project-static/docs/development/apps/api/setup.html +425 -155
- nautobot/project-static/docs/development/apps/api/testing.html +421 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +421 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +421 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +421 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +421 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +701 -130
- nautobot/project-static/docs/development/apps/api/views/base-template.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/index.html +423 -20
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +425 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +451 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/notes.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +421 -19
- nautobot/project-static/docs/development/apps/api/views/urls.html +421 -19
- nautobot/project-static/docs/development/apps/index.html +421 -19
- nautobot/project-static/docs/development/apps/migration/code-updates.html +422 -52
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +422 -20
- nautobot/project-static/docs/development/apps/migration/from-v1.html +421 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +421 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +421 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +421 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +424 -22
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9219 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9333 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9474 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9517 -0
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +424 -22
- nautobot/project-static/docs/development/core/application-registry.html +421 -19
- nautobot/project-static/docs/development/core/best-practices.html +421 -19
- nautobot/project-static/docs/development/core/bootstrap-ui.html +421 -19
- nautobot/project-static/docs/development/core/caching.html +421 -19
- nautobot/project-static/docs/development/core/controllers.html +423 -19
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +490 -45
- nautobot/project-static/docs/development/core/generic-views.html +421 -19
- nautobot/project-static/docs/development/core/getting-started.html +566 -179
- nautobot/project-static/docs/development/core/homepage.html +432 -30
- nautobot/project-static/docs/development/core/index.html +421 -19
- nautobot/project-static/docs/development/core/local-k8s.html +9453 -0
- nautobot/project-static/docs/development/core/model-checklist.html +424 -22
- nautobot/project-static/docs/development/core/model-features.html +421 -19
- nautobot/project-static/docs/development/core/natural-keys.html +421 -19
- nautobot/project-static/docs/development/core/navigation-menu.html +438 -26
- nautobot/project-static/docs/development/core/release-checklist.html +435 -45
- nautobot/project-static/docs/development/core/role-internals.html +421 -19
- nautobot/project-static/docs/development/core/settings.html +421 -19
- nautobot/project-static/docs/development/core/style-guide.html +421 -19
- nautobot/project-static/docs/development/core/templates.html +431 -22
- nautobot/project-static/docs/development/core/testing.html +421 -19
- nautobot/project-static/docs/development/core/ui-component-framework.html +11020 -0
- nautobot/project-static/docs/development/core/user-preferences.html +424 -22
- nautobot/project-static/docs/development/index.html +421 -19
- nautobot/project-static/docs/development/jobs/index.html +546 -160
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +421 -19
- nautobot/project-static/docs/index.html +421 -19
- nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
- nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
- nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
- nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
- nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
- nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +426 -20
- nautobot/project-static/docs/overview/design_philosophy.html +421 -19
- nautobot/project-static/docs/release-notes/index.html +445 -22
- nautobot/project-static/docs/release-notes/version-1.0.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.1.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.2.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.3.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.4.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.5.html +421 -19
- nautobot/project-static/docs/release-notes/version-1.6.html +634 -667
- nautobot/project-static/docs/release-notes/version-2.0.html +421 -19
- nautobot/project-static/docs/release-notes/version-2.1.html +421 -19
- nautobot/project-static/docs/release-notes/version-2.2.html +421 -19
- nautobot/project-static/docs/release-notes/version-2.3.html +684 -886
- nautobot/project-static/docs/release-notes/version-2.4.html +10007 -0
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +334 -270
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +421 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +421 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +423 -21
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +433 -32
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +421 -19
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +765 -180
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +434 -29
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +421 -19
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/index.html +426 -20
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +421 -19
- nautobot/project-static/docs/user-guide/administration/installation/services.html +421 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +421 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +442 -41
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +435 -66
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +435 -66
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +421 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +427 -21
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +457 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +447 -22
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9333 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +424 -22
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +421 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +424 -22
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9271 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9175 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9169 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9235 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +421 -19
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +421 -19
- nautobot/project-static/docs/user-guide/index.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +9575 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +426 -20
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9182 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9250 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +424 -22
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +489 -56
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +421 -19
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +421 -19
- nautobot/project-static/img/jinja_logo.svg +97 -0
- nautobot/project-static/js/forms.js +5 -0
- nautobot/project-static/js/nav_menu.js +2 -1
- nautobot/tenancy/api/serializers.py +0 -2
- nautobot/tenancy/factory.py +1 -1
- nautobot/tenancy/navigation.py +0 -29
- nautobot/tenancy/templates/tenancy/tenant.html +4 -91
- nautobot/tenancy/tests/test_filters.py +29 -134
- nautobot/tenancy/views.py +32 -23
- nautobot/users/admin.py +3 -1
- nautobot/users/api/serializers.py +4 -5
- nautobot/users/api/views.py +1 -1
- nautobot/users/forms.py +19 -0
- nautobot/users/templates/users/preferences.html +22 -0
- nautobot/users/tests/test_filters.py +1 -19
- nautobot/users/tests/test_views.py +57 -0
- nautobot/users/utils.py +8 -0
- nautobot/users/views.py +48 -11
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/filters.py +2 -20
- nautobot/virtualization/navigation.py +0 -48
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
- nautobot/virtualization/tests/test_filters.py +57 -183
- nautobot/virtualization/views.py +18 -15
- nautobot/wireless/__init__.py +0 -0
- nautobot/wireless/api/__init__.py +0 -0
- nautobot/wireless/api/serializers.py +44 -0
- nautobot/wireless/api/urls.py +20 -0
- nautobot/wireless/api/views.py +34 -0
- nautobot/wireless/apps.py +8 -0
- nautobot/wireless/choices.py +345 -0
- nautobot/wireless/factory.py +138 -0
- nautobot/wireless/filters.py +167 -0
- nautobot/wireless/forms.py +283 -0
- nautobot/wireless/homepage.py +19 -0
- nautobot/wireless/migrations/0001_initial.py +223 -0
- nautobot/wireless/migrations/__init__.py +0 -0
- nautobot/wireless/models.py +207 -0
- nautobot/wireless/navigation.py +105 -0
- nautobot/wireless/tables.py +244 -0
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +64 -0
- nautobot/wireless/tests/__init__.py +0 -0
- nautobot/wireless/tests/test_api.py +247 -0
- nautobot/wireless/tests/test_filters.py +54 -0
- nautobot/wireless/tests/test_models.py +22 -0
- nautobot/wireless/tests/test_views.py +378 -0
- nautobot/wireless/urls.py +13 -0
- nautobot/wireless/views.py +129 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/METADATA +11 -14
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/RECORD +674 -551
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/WHEEL +1 -1
- nautobot/core/utils/navigation.py +0 -54
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -57,6 +57,11 @@ class NautobotTemplatetagsHelperTest(TestCase):
|
|
|
57
57
|
self.assertEqual(helpers.placeholder([]), '<span class="text-muted">—</span>')
|
|
58
58
|
self.assertEqual(helpers.placeholder("something"), "something")
|
|
59
59
|
|
|
60
|
+
def test_pre_tag(self):
|
|
61
|
+
self.assertEqual(helpers.pre_tag(None), "<pre>None</pre>")
|
|
62
|
+
self.assertEqual(helpers.pre_tag([]), "<pre>[]</pre>")
|
|
63
|
+
self.assertEqual(helpers.pre_tag("something"), "<pre>something</pre>")
|
|
64
|
+
|
|
60
65
|
def test_add_html_id(self):
|
|
61
66
|
# Case where what we have isn't actually a HTML element but just a bare string
|
|
62
67
|
self.assertEqual(helpers.add_html_id("hello", "my-id"), "hello")
|
|
@@ -322,3 +327,14 @@ class NautobotTemplatetagsHelperTest(TestCase):
|
|
|
322
327
|
helpers.hyperlinked_object_target_new_tab(location, "foo"),
|
|
323
328
|
f'<a href="/dcim/locations/{location.pk}/" title="An important location" target="_blank" rel="noreferrer">{location!s}</a>',
|
|
324
329
|
)
|
|
330
|
+
|
|
331
|
+
def test_dbm(self):
|
|
332
|
+
self.assertEqual(
|
|
333
|
+
helpers.dbm(12),
|
|
334
|
+
"12 dBm",
|
|
335
|
+
)
|
|
336
|
+
self.assertEqual(
|
|
337
|
+
helpers.dbm(-85),
|
|
338
|
+
"-85 dBm",
|
|
339
|
+
)
|
|
340
|
+
self.assertEqual(helpers.dbm(None), helpers.placeholder(None))
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Test cases for nautobot.core.ui module."""
|
|
2
|
+
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
from django.template import Context
|
|
6
|
+
|
|
7
|
+
from nautobot.core.templatetags.helpers import HTML_NONE
|
|
8
|
+
from nautobot.core.testing import TestCase
|
|
9
|
+
from nautobot.core.ui.object_detail import BaseTextPanel, DataTablePanel, Panel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DataTablePanelTest(TestCase):
|
|
13
|
+
def test_init(self):
|
|
14
|
+
# Minimal arguments
|
|
15
|
+
DataTablePanel(context_data_key="data", weight=100)
|
|
16
|
+
|
|
17
|
+
# Conflicting arguments
|
|
18
|
+
with self.assertRaises(ValueError):
|
|
19
|
+
DataTablePanel(context_data_key="data", weight=100, columns=[1, 2, 3], context_columns_key="columns")
|
|
20
|
+
with self.assertRaises(ValueError):
|
|
21
|
+
DataTablePanel(
|
|
22
|
+
context_data_key="data",
|
|
23
|
+
weight=100,
|
|
24
|
+
column_headers=[1, 2, 3],
|
|
25
|
+
context_column_headers_key="column_headers",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Maximal arguments
|
|
29
|
+
DataTablePanel(context_data_key="data", weight=100, columns=[1, 2, 3], column_headers=["One", "Two", "Three"])
|
|
30
|
+
DataTablePanel(context_data_key="data", weight=100, context_columns_key="c", context_column_headers_key="ch")
|
|
31
|
+
|
|
32
|
+
def test_get_columns(self):
|
|
33
|
+
context = Context({"data": [{1: 1, 2: 2, 3: 3}, {1: 10, 2: 20, 3: 30}], "columns": [1, 3]})
|
|
34
|
+
|
|
35
|
+
self.assertEqual(DataTablePanel(context_data_key="data", weight=100).get_columns(context), [1, 2, 3])
|
|
36
|
+
self.assertEqual(
|
|
37
|
+
DataTablePanel(context_data_key="data", weight=100, columns=[1, 2]).get_columns(context), [1, 2]
|
|
38
|
+
)
|
|
39
|
+
self.assertEqual(
|
|
40
|
+
DataTablePanel(context_data_key="data", weight=100, context_columns_key="columns").get_columns(context),
|
|
41
|
+
[1, 3],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def test_get_column_headers(self):
|
|
45
|
+
context = Context(
|
|
46
|
+
{
|
|
47
|
+
"data": [{1: 1, 2: 2, 3: 3}, {1: 10, 2: 20, 3: 30}],
|
|
48
|
+
"columns": [1, 3],
|
|
49
|
+
"column_headers": ["One", "Three"],
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.assertEqual(DataTablePanel(context_data_key="data", weight=100).get_column_headers(context), [])
|
|
54
|
+
self.assertEqual(
|
|
55
|
+
DataTablePanel(context_data_key="data", weight=100, column_headers=["one", "two"]).get_column_headers(
|
|
56
|
+
context
|
|
57
|
+
),
|
|
58
|
+
["one", "two"],
|
|
59
|
+
)
|
|
60
|
+
self.assertEqual(
|
|
61
|
+
DataTablePanel(
|
|
62
|
+
context_data_key="data", weight=100, context_column_headers_key="column_headers"
|
|
63
|
+
).get_column_headers(context),
|
|
64
|
+
["One", "Three"],
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class BaseTextPanelTest(TestCase):
|
|
69
|
+
def test_init_set_object_params(self):
|
|
70
|
+
# Test default settings
|
|
71
|
+
panel = BaseTextPanel(weight=100)
|
|
72
|
+
self.assertEqual(panel.render_as, BaseTextPanel.RenderOptions.MARKDOWN)
|
|
73
|
+
self.assertTrue(panel.render_placeholder)
|
|
74
|
+
|
|
75
|
+
# Test initialization with custom arguments
|
|
76
|
+
panel = BaseTextPanel(weight=100, render_as=BaseTextPanel.RenderOptions.JSON, render_placeholder=False)
|
|
77
|
+
self.assertEqual(panel.render_as, BaseTextPanel.RenderOptions.JSON)
|
|
78
|
+
self.assertFalse(panel.render_placeholder)
|
|
79
|
+
|
|
80
|
+
@patch.object(Panel, "__init__")
|
|
81
|
+
def test_init_passes_args_and_kwargs(self, panel_init_mock):
|
|
82
|
+
custom_template_path = "custom_template_path.html"
|
|
83
|
+
|
|
84
|
+
BaseTextPanel(weight=100, body_content_template_path=custom_template_path)
|
|
85
|
+
|
|
86
|
+
panel_init_mock.assert_called_once_with(weight=100, body_content_template_path=custom_template_path)
|
|
87
|
+
|
|
88
|
+
@patch.object(BaseTextPanel, "get_value")
|
|
89
|
+
def test_render_body_content(self, get_value_mock):
|
|
90
|
+
test_cases = [
|
|
91
|
+
{
|
|
92
|
+
"render_as": BaseTextPanel.RenderOptions.JSON,
|
|
93
|
+
"value": {"key": "value"},
|
|
94
|
+
"expected_output": '<pre><code class="language-json">{ "key": "value" }</code></pre>',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"render_as": BaseTextPanel.RenderOptions.YAML,
|
|
98
|
+
"value": {"key": "value"},
|
|
99
|
+
"expected_output": '<pre><code class="language-yaml">key: value</code></pre>',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"render_as": BaseTextPanel.RenderOptions.MARKDOWN,
|
|
103
|
+
"value": "# Header",
|
|
104
|
+
"expected_output": "<h1>Header</h1>",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"render_as": BaseTextPanel.RenderOptions.CODE,
|
|
108
|
+
"value": "print('Hello, world!')",
|
|
109
|
+
"expected_output": "<pre>print('Hello, world!')</pre>",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"render_as": BaseTextPanel.RenderOptions.PLAINTEXT,
|
|
113
|
+
"value": "Simple text",
|
|
114
|
+
"expected_output": "Simple text",
|
|
115
|
+
},
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
for case in test_cases:
|
|
119
|
+
with self.subTest(render_as=case["render_as"]):
|
|
120
|
+
panel = BaseTextPanel(weight=100, render_as=case["render_as"])
|
|
121
|
+
|
|
122
|
+
get_value_mock.return_value = case["value"]
|
|
123
|
+
context = Context()
|
|
124
|
+
|
|
125
|
+
result = panel.render_body_content(context)
|
|
126
|
+
|
|
127
|
+
self.assertHTMLEqual(result, case["expected_output"])
|
|
128
|
+
|
|
129
|
+
@patch.object(BaseTextPanel, "get_value")
|
|
130
|
+
def test_render_body_content_render_placeholder(self, get_value_mock):
|
|
131
|
+
get_value_mock.return_value = ""
|
|
132
|
+
context = Context()
|
|
133
|
+
|
|
134
|
+
panel = BaseTextPanel(weight=100, render_as=BaseTextPanel.RenderOptions.PLAINTEXT)
|
|
135
|
+
|
|
136
|
+
self.assertHTMLEqual(panel.render_body_content(context), HTML_NONE)
|
|
137
|
+
|
|
138
|
+
@patch.object(BaseTextPanel, "get_value")
|
|
139
|
+
def test_render_body_content_not_render_placeholder(self, get_value_mock):
|
|
140
|
+
get_value_mock.return_value = ""
|
|
141
|
+
context = Context()
|
|
142
|
+
|
|
143
|
+
panel = BaseTextPanel(weight=100, render_as=BaseTextPanel.RenderOptions.PLAINTEXT, render_placeholder=False)
|
|
144
|
+
|
|
145
|
+
self.assertHTMLEqual(panel.render_body_content(context), "")
|
|
146
|
+
|
|
147
|
+
def test_get_value(self):
|
|
148
|
+
panel = BaseTextPanel(weight=100)
|
|
149
|
+
with self.assertRaises(NotImplementedError):
|
|
150
|
+
panel.get_value({})
|
|
@@ -20,7 +20,6 @@ from nautobot.dcim import filters as dcim_filters, forms as dcim_forms, models a
|
|
|
20
20
|
from nautobot.extras import models as extras_models, utils as extras_utils
|
|
21
21
|
from nautobot.extras.choices import ObjectChangeActionChoices, RelationshipTypeChoices
|
|
22
22
|
from nautobot.extras.models import ObjectChange
|
|
23
|
-
from nautobot.extras.registry import registry
|
|
24
23
|
from nautobot.ipam import models as ipam_models
|
|
25
24
|
|
|
26
25
|
from example_app.models import ExampleModel
|
|
@@ -268,14 +267,6 @@ class GetFooForModelTest(TestCase):
|
|
|
268
267
|
lookup.get_model_for_view_name("unknown:plugins:example_app:examplemodel_list")
|
|
269
268
|
self.assertEqual(str(err.exception), "Unexpected View Name: unknown:plugins:example_app:examplemodel_list")
|
|
270
269
|
|
|
271
|
-
def test_get_table_class_string_from_view_name(self):
|
|
272
|
-
# Testing UIViewSet
|
|
273
|
-
self.assertEqual(lookup.get_table_class_string_from_view_name("circuits:circuit_list"), "CircuitTable")
|
|
274
|
-
# Testing Legacy View
|
|
275
|
-
self.assertEqual(lookup.get_table_class_string_from_view_name("dcim:location_list"), "LocationTable")
|
|
276
|
-
# Testing unconventional table name
|
|
277
|
-
self.assertEqual(lookup.get_table_class_string_from_view_name("ipam:prefix_list"), "PrefixDetailTable")
|
|
278
|
-
|
|
279
270
|
|
|
280
271
|
class IsTaggableTest(TestCase):
|
|
281
272
|
def test_is_taggable_true(self):
|
|
@@ -882,22 +873,6 @@ class MergeDictsWithoutCollisionTest(TestCase):
|
|
|
882
873
|
self.assertEqual(str(err.exception), 'Conflicting values for key "a": (1, 2)')
|
|
883
874
|
|
|
884
875
|
|
|
885
|
-
class NavigationRelatedUtils(TestCase):
|
|
886
|
-
def get_all_new_ui_ready_route(self):
|
|
887
|
-
ui_ready_routes = [
|
|
888
|
-
"^\\Z",
|
|
889
|
-
"^dcim/device\\-types/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z",
|
|
890
|
-
"^dcim/device\\-types/\\Z",
|
|
891
|
-
"^dcim/devices/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z",
|
|
892
|
-
"^dcim/devices/\\Z",
|
|
893
|
-
"^dcim/locations/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z",
|
|
894
|
-
"^dcim/locations/\\Z",
|
|
895
|
-
"^ipam/ip\\-addresses/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z",
|
|
896
|
-
"^ipam/ip\\-addresses/\\Z",
|
|
897
|
-
]
|
|
898
|
-
self.assertEqual(sorted(ui_ready_routes), sorted(list(registry["new_ui_ready_routes"])))
|
|
899
|
-
|
|
900
|
-
|
|
901
876
|
class TestMigrationUtils(TestCase):
|
|
902
877
|
def test_update_object_change_ct_for_replaced_models(self):
|
|
903
878
|
"""Assert update and update reverse of ObjectChange"""
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import re
|
|
2
3
|
from unittest import mock, skipIf
|
|
3
4
|
import urllib.parse
|
|
@@ -11,19 +12,22 @@ from django.test.utils import override_script_prefix
|
|
|
11
12
|
from django.urls import get_script_prefix, reverse
|
|
12
13
|
from prometheus_client.parser import text_string_to_metric_families
|
|
13
14
|
|
|
15
|
+
from nautobot.circuits.models import Circuit, CircuitType, Provider
|
|
14
16
|
from nautobot.core.constants import GLOBAL_SEARCH_EXCLUDE_LIST
|
|
15
17
|
from nautobot.core.testing import TestCase
|
|
16
18
|
from nautobot.core.testing.api import APITestCase
|
|
19
|
+
from nautobot.core.testing.context import load_event_broker_override_settings
|
|
17
20
|
from nautobot.core.testing.utils import extract_page_body
|
|
18
21
|
from nautobot.core.utils.permissions import get_permission_for_model
|
|
19
22
|
from nautobot.core.views import NautobotMetricsView
|
|
20
23
|
from nautobot.core.views.mixins import GetReturnURLMixin
|
|
21
24
|
from nautobot.dcim.models.locations import Location
|
|
22
25
|
from nautobot.extras.choices import CustomFieldTypeChoices
|
|
23
|
-
from nautobot.extras.models import FileProxy
|
|
26
|
+
from nautobot.extras.models import FileProxy, Status
|
|
24
27
|
from nautobot.extras.models.customfields import CustomField, CustomFieldChoice
|
|
25
28
|
from nautobot.extras.registry import registry
|
|
26
29
|
from nautobot.users.models import ObjectPermission
|
|
30
|
+
from nautobot.users.utils import serialize_user_without_config_and_views
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
class GetReturnURLMixinTestCase(TestCase):
|
|
@@ -318,8 +322,29 @@ class NavAppsUITestCase(TestCase):
|
|
|
318
322
|
def setUp(self):
|
|
319
323
|
super().setUp()
|
|
320
324
|
|
|
321
|
-
self.
|
|
322
|
-
self.
|
|
325
|
+
self.apps_marketplace_url = reverse("apps:apps_marketplace")
|
|
326
|
+
self.apps_marketplace_item_weight = (
|
|
327
|
+
100 # TODO: not easy to introspect from the nav menu struct, so hard-code it here for now
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
self.apps_list_url = reverse("apps:apps_list")
|
|
331
|
+
self.apps_list_item_weight = (
|
|
332
|
+
200 # TODO: not easy to introspect from the nav menu struct, so hard-code it here for now
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
def test_apps_marketplace_visible(self):
|
|
336
|
+
"""The "Apps Marketplace" menu item should be available to an authenticated user regardless of permissions."""
|
|
337
|
+
response = self.client.get(reverse("home"))
|
|
338
|
+
self.assertContains(
|
|
339
|
+
response,
|
|
340
|
+
f"""
|
|
341
|
+
<a href="{self.apps_marketplace_url}"
|
|
342
|
+
data-item-weight="{self.apps_marketplace_item_weight}">
|
|
343
|
+
Apps Marketplace
|
|
344
|
+
</a>
|
|
345
|
+
""",
|
|
346
|
+
html=True,
|
|
347
|
+
)
|
|
323
348
|
|
|
324
349
|
def test_installed_apps_visible(self):
|
|
325
350
|
"""The "Installed Apps" menu item should be available to an authenticated user regardless of permissions."""
|
|
@@ -327,8 +352,8 @@ class NavAppsUITestCase(TestCase):
|
|
|
327
352
|
self.assertContains(
|
|
328
353
|
response,
|
|
329
354
|
f"""
|
|
330
|
-
<a href="{self.
|
|
331
|
-
data-item-weight="{self.
|
|
355
|
+
<a href="{self.apps_list_url}"
|
|
356
|
+
data-item-weight="{self.apps_list_item_weight}">
|
|
332
357
|
Installed Apps
|
|
333
358
|
</a>
|
|
334
359
|
""",
|
|
@@ -398,6 +423,52 @@ class LoginUITestCase(TestCase):
|
|
|
398
423
|
response = self.client.get(url)
|
|
399
424
|
self.assertHttpStatus(response, 403)
|
|
400
425
|
|
|
426
|
+
@load_event_broker_override_settings(
|
|
427
|
+
EVENT_BROKERS={
|
|
428
|
+
"SyslogEventBroker": {
|
|
429
|
+
"CLASS": "nautobot.core.events.SyslogEventBroker",
|
|
430
|
+
"TOPICS": {
|
|
431
|
+
"INCLUDE": ["*"],
|
|
432
|
+
},
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
)
|
|
436
|
+
def test_login_logout(self):
|
|
437
|
+
self.client.logout()
|
|
438
|
+
self.user.set_password("pass")
|
|
439
|
+
self.user.save()
|
|
440
|
+
|
|
441
|
+
with self.assertLogs("nautobot.events") as cm:
|
|
442
|
+
self.client.post(
|
|
443
|
+
reverse("login"),
|
|
444
|
+
data={
|
|
445
|
+
"username": self.user.username,
|
|
446
|
+
"password": "pass",
|
|
447
|
+
},
|
|
448
|
+
)
|
|
449
|
+
self.user.refresh_from_db()
|
|
450
|
+
payload = serialize_user_without_config_and_views(self.user)
|
|
451
|
+
self.assertEqual(
|
|
452
|
+
cm.output,
|
|
453
|
+
[f"INFO:nautobot.events.nautobot.users.user.login:{json.dumps(payload, indent=4)}"],
|
|
454
|
+
)
|
|
455
|
+
self.assertTrue(self.user.is_authenticated)
|
|
456
|
+
self.assertNotIn("password", cm.output)
|
|
457
|
+
self.assertNotIn("pass", cm.output)
|
|
458
|
+
|
|
459
|
+
with self.assertLogs("nautobot.events") as cm:
|
|
460
|
+
self.client.get(
|
|
461
|
+
reverse("logout"),
|
|
462
|
+
)
|
|
463
|
+
self.user.refresh_from_db()
|
|
464
|
+
payload = serialize_user_without_config_and_views(self.user)
|
|
465
|
+
self.assertEqual(
|
|
466
|
+
cm.output,
|
|
467
|
+
[f"INFO:nautobot.events.nautobot.users.user.logout:{json.dumps(payload, indent=4)}"],
|
|
468
|
+
)
|
|
469
|
+
self.assertNotIn("password", cm.output)
|
|
470
|
+
self.assertNotIn("pass", cm.output)
|
|
471
|
+
|
|
401
472
|
|
|
402
473
|
class MetricsViewTestCase(TestCase):
|
|
403
474
|
def query_and_parse_metrics(self):
|
|
@@ -593,33 +664,54 @@ class ExampleViewWithCustomPermissionsTest(TestCase):
|
|
|
593
664
|
self.user.is_staff = True
|
|
594
665
|
self.user.save()
|
|
595
666
|
response = self.client.get(url)
|
|
596
|
-
self.assertBodyContains(response, "You are viewing a table of example models")
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
class SearchRobotsTestCase(TestCase):
|
|
600
|
-
def test_robots_disallowed(self):
|
|
601
|
-
"""
|
|
602
|
-
Test that the robots.txt file is accessible to all users and defaults to disallowing all bots.
|
|
603
|
-
"""
|
|
604
|
-
url = reverse("robots_txt")
|
|
605
|
-
response = self.client.get(url)
|
|
606
667
|
self.assertHttpStatus(response, 200)
|
|
607
|
-
|
|
608
|
-
self.
|
|
668
|
+
response_body = response.content.decode(response.charset)
|
|
669
|
+
self.assertIn("You are viewing a table of example models", response_body)
|
|
609
670
|
|
|
610
|
-
url = reverse("home")
|
|
611
|
-
response = self.client.get(url)
|
|
612
|
-
self.assertContains(response, '<meta name="robots" content="noindex, nofollow">', html=True)
|
|
613
671
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
672
|
+
class TestObjectDetailView(TestCase):
|
|
673
|
+
@override_settings(PAGINATE_COUNT=5)
|
|
674
|
+
def test_object_table_panel(self):
|
|
675
|
+
provider = Provider.objects.create(name="A Test Provider 1")
|
|
676
|
+
circuit_type = CircuitType.objects.create(
|
|
677
|
+
name="A Test Circuit Type",
|
|
678
|
+
)
|
|
679
|
+
circuit_status = Status.objects.get_for_model(Circuit).first()
|
|
680
|
+
|
|
681
|
+
circuits = [
|
|
682
|
+
Circuit(
|
|
683
|
+
provider=provider,
|
|
684
|
+
cid=f"00121{x}",
|
|
685
|
+
circuit_type=circuit_type,
|
|
686
|
+
status=circuit_status,
|
|
687
|
+
)
|
|
688
|
+
for x in range(10)
|
|
689
|
+
]
|
|
690
|
+
Circuit.objects.bulk_create(circuits)
|
|
622
691
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
self.
|
|
692
|
+
self.add_permissions("circuits.view_provider", "circuits.view_circuit")
|
|
693
|
+
url = reverse("circuits:provider", args=(provider.pk,))
|
|
694
|
+
response = self.client.get(f"{url}?tab=main")
|
|
695
|
+
self.assertHttpStatus(response, 200)
|
|
696
|
+
response_data = response.content.decode(response.charset)
|
|
697
|
+
view_move_url = reverse("circuits:circuit_list") + f"?provider={provider.id}"
|
|
698
|
+
|
|
699
|
+
# Assert Badge Count in table panel header
|
|
700
|
+
panel_header = f"""<div class="panel-heading"><strong>Circuits</strong> <a href="{view_move_url}" class="badge badge-primary">10</a></div>"""
|
|
701
|
+
self.assertInHTML(panel_header, response_data)
|
|
702
|
+
|
|
703
|
+
# Assert view X more btn
|
|
704
|
+
view_more_btn = f"""<a href="{view_move_url}"><span class="mdi mdi-dots-horizontal" aria-hidden="true"></span>View 5 more circuits</a>"""
|
|
705
|
+
self.assertInHTML(view_more_btn, response_data)
|
|
706
|
+
|
|
707
|
+
# Validate Copy btn on all rows excluding empty rows
|
|
708
|
+
name_copy = f"""
|
|
709
|
+
<span class="hover_copy">
|
|
710
|
+
<span id="_value_name">{provider.name}</span>
|
|
711
|
+
<button class="btn btn-inline btn-default hover_copy_button" data-clipboard-target="#_value_name">
|
|
712
|
+
<span class="mdi mdi-content-copy"></span>
|
|
713
|
+
</button>
|
|
714
|
+
</span>"""
|
|
715
|
+
self.assertInHTML(name_copy, response_data)
|
|
716
|
+
# ASN do not have a value, therefore no copy btn
|
|
717
|
+
self.assertNotIn("#asn_copy", response_data)
|
|
File without changes
|
nautobot/core/ui/base.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Common base classes and utilities for defining the Nautobot UI."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PermissionsMixin:
|
|
5
|
+
"""Ensure permissions through init."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, permissions=None):
|
|
8
|
+
"""Ensure permissions."""
|
|
9
|
+
if permissions is not None and not isinstance(permissions, (list, tuple)):
|
|
10
|
+
raise TypeError("Permissions must be passed as a tuple or list.")
|
|
11
|
+
self.permissions = set(permissions) if permissions else None
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""ChoiceSets for Nautobot UI Framework."""
|
|
2
|
+
|
|
3
|
+
from nautobot.core.choices import ChoiceSet
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LayoutChoices(ChoiceSet):
|
|
7
|
+
"""Page (or more properly tab) column layout choices.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
TWO_OVER_ONE (str): Half-width panels will be above full-width panels (value: 2-over-1)
|
|
11
|
+
ONE_OVER_TWO (str): Full-width panels will be above half-width panels (value: 1-over-2)
|
|
12
|
+
|
|
13
|
+
DEFAULT (str): Two columns of half-width panels on top; full-width panels below. (value of TWO_OVER_ONE)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
TWO_OVER_ONE = "2-over-1"
|
|
17
|
+
ONE_OVER_TWO = "1-over-2"
|
|
18
|
+
|
|
19
|
+
DEFAULT = TWO_OVER_ONE
|
|
20
|
+
|
|
21
|
+
CHOICES = (
|
|
22
|
+
(TWO_OVER_ONE, "Two Columns over One Column"),
|
|
23
|
+
(ONE_OVER_TWO, "One Column over Two Columns"),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SectionChoices(ChoiceSet):
|
|
28
|
+
"""Sections of a Layout to assign panels to. Placement of panels is determined by [`LayoutChoices`](./ui.md#nautobot.apps.ui.LayoutChoices) set on `Tab.layout`
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
LEFT_HALF (str): Left side, half-width (value: left-half)
|
|
32
|
+
RIGHT_HALF (str): Right side, half-width (value: right-half)
|
|
33
|
+
FULL_WIDTH (str): Full width (value: full-width)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
LEFT_HALF = "left-half"
|
|
37
|
+
RIGHT_HALF = "right-half"
|
|
38
|
+
FULL_WIDTH = "full-width"
|
|
39
|
+
|
|
40
|
+
CHOICES = (
|
|
41
|
+
(LEFT_HALF, "Left half of page"),
|
|
42
|
+
(RIGHT_HALF, "Right half of page"),
|
|
43
|
+
(FULL_WIDTH, "Full width of page"),
|
|
44
|
+
)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Base classes and utilities for defining the Nautobot home page."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from .base import PermissionsMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HomePageBase(ABC):
|
|
9
|
+
"""Base class for homepage layout classes."""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def initial_dict(self): # to be implemented by each subclass
|
|
14
|
+
return {}
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def fixed_fields(self): # to be implemented by subclass
|
|
19
|
+
return ()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class HomePagePanel(HomePageBase, PermissionsMixin):
|
|
23
|
+
"""Defines properties that can be used for a panel."""
|
|
24
|
+
|
|
25
|
+
items = None
|
|
26
|
+
template_path = None
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def initial_dict(self):
|
|
30
|
+
return {
|
|
31
|
+
"custom_template": self.custom_template,
|
|
32
|
+
"custom_data": self.custom_data,
|
|
33
|
+
"weight": self.weight,
|
|
34
|
+
"items": {},
|
|
35
|
+
"permissions": self.permissions,
|
|
36
|
+
"template_path": self.template_path,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def fixed_fields(self):
|
|
41
|
+
return ()
|
|
42
|
+
|
|
43
|
+
def __init__(self, name, permissions=None, custom_data=None, custom_template=None, items=None, weight=1000):
|
|
44
|
+
"""
|
|
45
|
+
Ensure panel properties.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
name (str): The name of the panel.
|
|
49
|
+
permissions (list): The permissions required to view this panel.
|
|
50
|
+
custom_data (dict): Custom data to be passed to the custom template.
|
|
51
|
+
custom_template (str): Name of custom template.
|
|
52
|
+
items (list): List of items to be rendered in this panel.
|
|
53
|
+
weight (int): The weight of this panel.
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(permissions)
|
|
56
|
+
self.custom_data = custom_data
|
|
57
|
+
self.custom_template = custom_template
|
|
58
|
+
self.name = name
|
|
59
|
+
self.weight = weight
|
|
60
|
+
|
|
61
|
+
if items is not None and custom_template is not None:
|
|
62
|
+
raise ValueError("Cannot specify items and custom_template at the same time.")
|
|
63
|
+
if items is not None:
|
|
64
|
+
if not isinstance(items, (list, tuple)):
|
|
65
|
+
raise TypeError("Items must be passed as a tuple or list.")
|
|
66
|
+
elif not all(isinstance(item, (HomePageGroup, HomePageItem)) for item in items):
|
|
67
|
+
raise TypeError("All items defined in a panel must be an instance of HomePageGroup or HomePageItem")
|
|
68
|
+
self.items = items
|
|
69
|
+
else:
|
|
70
|
+
self.items = []
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class HomePageGroup(HomePageBase, PermissionsMixin):
|
|
74
|
+
"""Defines properties that can be used for a panel group."""
|
|
75
|
+
|
|
76
|
+
items = []
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def initial_dict(self):
|
|
80
|
+
return {
|
|
81
|
+
"items": {},
|
|
82
|
+
"permissions": self.permissions,
|
|
83
|
+
"weight": self.weight,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def fixed_fields(self):
|
|
88
|
+
return ()
|
|
89
|
+
|
|
90
|
+
def __init__(self, name, permissions=None, items=None, weight=1000):
|
|
91
|
+
"""
|
|
92
|
+
Ensure group properties.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
name (str): The name of the group.
|
|
96
|
+
permissions (list): The permissions required to view this group.
|
|
97
|
+
items (list): List of items to be rendered in this group.
|
|
98
|
+
weight (int): The weight of this group.
|
|
99
|
+
"""
|
|
100
|
+
super().__init__(permissions)
|
|
101
|
+
self.name = name
|
|
102
|
+
self.weight = weight
|
|
103
|
+
|
|
104
|
+
if items is not None:
|
|
105
|
+
if not isinstance(items, (list, tuple)):
|
|
106
|
+
raise TypeError("Items must be passed as a tuple or list.")
|
|
107
|
+
elif not all(isinstance(item, HomePageItem) for item in items):
|
|
108
|
+
raise TypeError("All items defined in a group must be an instance of HomePageItem")
|
|
109
|
+
self.items = items
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class HomePageItem(HomePageBase, PermissionsMixin):
|
|
113
|
+
"""Defines properties that can be used for a panel item."""
|
|
114
|
+
|
|
115
|
+
items = []
|
|
116
|
+
template_path = None
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def initial_dict(self):
|
|
120
|
+
return {
|
|
121
|
+
"custom_template": self.custom_template,
|
|
122
|
+
"custom_data": self.custom_data,
|
|
123
|
+
"description": self.description,
|
|
124
|
+
"link": self.link,
|
|
125
|
+
"model": self.model,
|
|
126
|
+
"permissions": self.permissions,
|
|
127
|
+
"template_path": self.template_path,
|
|
128
|
+
"weight": self.weight,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def fixed_fields(self):
|
|
133
|
+
return ()
|
|
134
|
+
|
|
135
|
+
def __init__(
|
|
136
|
+
self,
|
|
137
|
+
name,
|
|
138
|
+
link=None,
|
|
139
|
+
model=None,
|
|
140
|
+
custom_template=None,
|
|
141
|
+
custom_data=None,
|
|
142
|
+
description=None,
|
|
143
|
+
permissions=None,
|
|
144
|
+
weight=1000,
|
|
145
|
+
):
|
|
146
|
+
"""
|
|
147
|
+
Ensure item properties.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
name (str): The name of the item.
|
|
151
|
+
link (str): The link to be used for this item.
|
|
152
|
+
model (str): The model to being used for this item to calculate the total count of objects.
|
|
153
|
+
custom_template (str): Name of custom template.
|
|
154
|
+
custom_data (dict): Custom data to be passed to the custom template.
|
|
155
|
+
"""
|
|
156
|
+
super().__init__(permissions)
|
|
157
|
+
|
|
158
|
+
self.name = name
|
|
159
|
+
self.custom_template = custom_template
|
|
160
|
+
self.custom_data = custom_data
|
|
161
|
+
self.description = description
|
|
162
|
+
self.link = link
|
|
163
|
+
self.model = model
|
|
164
|
+
self.weight = weight
|
|
165
|
+
|
|
166
|
+
if model is not None and custom_template is not None:
|
|
167
|
+
raise ValueError("Cannot specify model and custom_template at the same time.")
|