nautobot 2.0.0a2__py3-none-any.whl → 2.0.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.
- nautobot/__init__.py +1 -5
- nautobot/apps/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -119
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/choices.py +0 -2
- nautobot/circuits/filters.py +7 -6
- nautobot/circuits/forms.py +3 -73
- nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
- nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
- nautobot/circuits/migrations/0003_auto_slug.py +0 -1
- nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
- nautobot/circuits/migrations/0005_providernetwork.py +0 -1
- nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
- nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
- nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
- nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
- nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
- nautobot/circuits/migrations/0012_created_datetime.py +0 -1
- nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
- nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
- nautobot/circuits/migrations/0016_tagsfield.py +34 -0
- nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
- nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
- nautobot/circuits/models.py +3 -93
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +42 -5
- nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/provider_create.html +0 -1
- nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
- nautobot/circuits/tests/integration/test_relationships.py +13 -16
- nautobot/circuits/tests/test_api.py +13 -43
- nautobot/circuits/tests/test_filters.py +20 -15
- nautobot/circuits/tests/test_models.py +7 -3
- nautobot/circuits/tests/test_views.py +57 -67
- nautobot/circuits/views.py +18 -9
- nautobot/core/api/__init__.py +8 -2
- nautobot/core/api/authentication.py +0 -3
- nautobot/core/api/fields.py +15 -6
- nautobot/core/api/filter_backends.py +3 -2
- nautobot/core/api/metadata.py +237 -30
- nautobot/core/api/mixins.py +94 -0
- nautobot/core/api/pagination.py +3 -3
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +47 -3
- nautobot/core/api/serializers.py +377 -37
- nautobot/core/api/urls.py +11 -3
- nautobot/core/api/utils.py +174 -2
- nautobot/core/api/versioning.py +32 -10
- nautobot/core/api/views.py +266 -75
- nautobot/core/apps/__init__.py +138 -221
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -13
- nautobot/core/celery/control.py +46 -0
- nautobot/core/celery/encoders.py +53 -0
- nautobot/core/celery/log.py +38 -0
- nautobot/core/celery/schedulers.py +23 -4
- nautobot/core/celery/task.py +1 -16
- nautobot/core/checks.py +0 -27
- nautobot/core/choices.py +21 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -2
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +25 -43
- nautobot/core/context_processors.py +12 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/forms/__init__.py +0 -4
- nautobot/core/forms/fields.py +39 -68
- nautobot/core/forms/forms.py +27 -27
- nautobot/core/forms/utils.py +7 -59
- nautobot/core/forms/widgets.py +0 -1
- nautobot/core/graphql/__init__.py +2 -2
- nautobot/core/graphql/schema.py +4 -27
- nautobot/core/jobs/__init__.py +75 -0
- nautobot/core/management/commands/build_ui.py +255 -0
- nautobot/core/management/commands/celery.py +0 -1
- nautobot/core/management/commands/generate_test_data.py +18 -13
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/management/commands/validate_models.py +0 -1
- nautobot/core/middleware.py +0 -1
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -46
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +1 -19
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +9 -10
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +81 -53
- nautobot/core/tables.py +5 -5
- nautobot/core/tasks.py +4 -7
- nautobot/core/templates/base.html +1 -49
- nautobot/core/templates/base_django.html +49 -0
- nautobot/core/templates/base_react.html +55 -0
- nautobot/core/templates/buttons/export.html +6 -4
- nautobot/core/templates/generic/object_bulk_create.html +10 -21
- nautobot/core/templates/generic/object_list.html +4 -1
- nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/javascript.html +0 -14
- nautobot/core/templates/inc/nav_menu.html +28 -33
- nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
- nautobot/core/templates/inc/relationships_table_rows.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +8 -25
- nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
- nautobot/core/templates/rest_framework/api.html +8 -0
- nautobot/core/templatetags/buttons.py +32 -29
- nautobot/core/templatetags/helpers.py +1 -1
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +365 -47
- nautobot/core/testing/filters.py +12 -7
- nautobot/core/testing/integration.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -12
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +28 -51
- nautobot/core/tests/integration/test_filters.py +17 -8
- nautobot/core/tests/integration/test_navbar.py +11 -34
- nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
- nautobot/core/tests/nautobot_config.py +2 -3
- nautobot/core/tests/runner.py +0 -1
- nautobot/core/tests/test_api.py +290 -24
- nautobot/core/tests/test_authentication.py +57 -14
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_choices.py +0 -1
- nautobot/core/tests/test_filters.py +117 -110
- nautobot/core/tests/test_forms.py +47 -110
- nautobot/core/tests/test_graphql.py +158 -135
- nautobot/core/tests/test_logging.py +4 -1
- nautobot/core/tests/test_managers.py +3 -5
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_ordering.py +0 -2
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +7 -4
- nautobot/core/tests/test_utils.py +112 -78
- nautobot/core/tests/test_views.py +12 -17
- nautobot/core/tests/test_views_utils.py +6 -9
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +13 -20
- nautobot/core/utils/filtering.py +53 -9
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +23 -116
- nautobot/core/views/__init__.py +1 -2
- nautobot/core/views/generic.py +131 -119
- nautobot/core/views/mixins.py +53 -62
- nautobot/core/views/paginator.py +0 -1
- nautobot/core/views/renderers.py +14 -12
- nautobot/core/views/utils.py +87 -4
- nautobot/dcim/api/serializers.py +160 -672
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -46
- nautobot/dcim/choices.py +2 -25
- nautobot/dcim/elevations.py +0 -1
- nautobot/dcim/factory.py +15 -4
- nautobot/dcim/filters/__init__.py +42 -13
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +58 -797
- nautobot/dcim/management/commands/trace_paths.py +0 -1
- nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
- nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
- nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
- nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
- nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
- nautobot/dcim/migrations/0006_auto_slug.py +0 -1
- nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
- nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
- nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
- nautobot/dcim/migrations/0010_interface_status.py +0 -1
- nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
- nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
- nautobot/dcim/migrations/0013_location_location_type.py +0 -1
- nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
- nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
- nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
- nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
- nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
- nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
- nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
- nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
- nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
- nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
- nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
- nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
- nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
- nautobot/dcim/migrations/0033_created_datetime.py +0 -1
- nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
- nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
- nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
- nautobot/dcim/migrations/0039_remove_slug.py +24 -0
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +4 -35
- nautobot/dcim/models/device_component_templates.py +7 -2
- nautobot/dcim/models/device_components.py +26 -203
- nautobot/dcim/models/devices.py +30 -152
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -51
- nautobot/dcim/models/racks.py +7 -86
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/devices.py +8 -5
- nautobot/dcim/tables/devicetypes.py +1 -1
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +2 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/device.html +15 -4
- nautobot/dcim/templates/dcim/device_edit.html +6 -0
- nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +4 -0
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/location.html +16 -1
- nautobot/dcim/templates/dcim/locationtype.html +15 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/rackgroup.html +0 -12
- nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
- nautobot/dcim/tests/test_api.py +202 -130
- nautobot/dcim/tests/test_cablepaths.py +47 -42
- nautobot/dcim/tests/test_filters.py +156 -134
- nautobot/dcim/tests/test_forms.py +12 -213
- nautobot/dcim/tests/test_graphql.py +8 -3
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +208 -158
- nautobot/dcim/tests/test_natural_ordering.py +12 -14
- nautobot/dcim/tests/test_signals.py +7 -4
- nautobot/dcim/tests/test_views.py +270 -264
- nautobot/dcim/urls.py +21 -26
- nautobot/dcim/views.py +14 -156
- nautobot/docs/additional-features/caching.md +6 -87
- nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
- nautobot/docs/additional-features/jobs.md +179 -197
- nautobot/docs/administration/nautobot-server.md +9 -24
- nautobot/docs/administration/nautobot-shell.md +6 -6
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/index.md +9 -9
- nautobot/docs/configuration/optional-settings.md +32 -61
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/best-practices.md +2 -1
- nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +56 -6
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/release-checklist.md +3 -3
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/development/templates.md +2 -1
- nautobot/docs/docker/index.md +16 -14
- nautobot/docs/index.md +7 -3
- nautobot/docs/installation/index.md +4 -1
- nautobot/docs/installation/migrating-from-netbox.md +12 -43
- nautobot/docs/installation/migrating-from-postgresql.md +1 -1
- nautobot/docs/installation/nautobot.md +1 -1
- nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
- nautobot/docs/installation/upgrading.md +5 -2
- nautobot/docs/models/dcim/device.md +3 -0
- nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
- nautobot/docs/models/extras/computedfield.md +4 -4
- nautobot/docs/models/extras/dynamicgroup.md +9 -9
- nautobot/docs/models/extras/gitrepository.md +3 -0
- nautobot/docs/models/extras/job.md +1 -0
- nautobot/docs/models/extras/jobbutton.md +18 -13
- nautobot/docs/models/extras/jobhook.md +7 -4
- nautobot/docs/models/extras/jobresult.md +6 -2
- nautobot/docs/models/extras/relationship.md +2 -2
- nautobot/docs/models/extras/status.md +6 -19
- nautobot/docs/models/ipam/ipaddress.md +3 -0
- nautobot/docs/models/ipam/vrf.md +0 -3
- nautobot/docs/models/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +92 -24
- nautobot/docs/release-notes/version-1.5.md +96 -0
- nautobot/docs/release-notes/version-2.0.md +216 -0
- nautobot/docs/requirements.txt +5 -4
- nautobot/docs/rest-api/overview.md +384 -215
- nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
- nautobot/extras/admin.py +3 -5
- nautobot/extras/api/customfields.py +15 -39
- nautobot/extras/api/fields.py +0 -11
- nautobot/extras/api/mixins.py +45 -0
- nautobot/extras/api/relationships.py +63 -159
- nautobot/extras/api/serializers.py +165 -706
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +295 -282
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -22
- nautobot/extras/constants.py +9 -3
- nautobot/extras/datasources/__init__.py +2 -0
- nautobot/extras/datasources/git.py +135 -186
- nautobot/extras/datasources/registry.py +25 -35
- nautobot/extras/factory.py +1 -3
- nautobot/extras/filters/__init__.py +49 -47
- nautobot/extras/filters/mixins.py +10 -8
- nautobot/extras/forms/forms.py +72 -148
- nautobot/extras/forms/mixins.py +34 -57
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -566
- nautobot/extras/management/__init__.py +55 -48
- nautobot/extras/management/commands/renaturalize.py +0 -1
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/management/commands/webhook_receiver.py +0 -1
- nautobot/extras/managers.py +30 -7
- nautobot/extras/migrations/0001_initial_part_1.py +0 -1
- nautobot/extras/migrations/0002_initial_part_2.py +0 -1
- nautobot/extras/migrations/0003_initial_part_3.py +0 -1
- nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
- nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
- nautobot/extras/migrations/0006_graphqlquery.py +0 -1
- nautobot/extras/migrations/0007_configcontextschema.py +0 -1
- nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
- nautobot/extras/migrations/0009_computedfield.py +0 -1
- nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
- nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
- nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
- nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
- nautobot/extras/migrations/0014_auto_slug.py +0 -1
- nautobot/extras/migrations/0015_scheduled_job.py +0 -1
- nautobot/extras/migrations/0016_secret.py +0 -1
- nautobot/extras/migrations/0017_joblogentry.py +0 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
- nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
- nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
- nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
- nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
- nautobot/extras/migrations/0023_job_model.py +0 -1
- nautobot/extras/migrations/0024_job_data_migration.py +0 -1
- nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
- nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
- nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
- nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
- nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
- nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
- nautobot/extras/migrations/0031_tag_content_types.py +0 -1
- nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
- nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
- nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
- nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
- nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
- nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
- nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
- nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
- nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
- nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
- nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
- nautobot/extras/migrations/0043_note.py +0 -1
- nautobot/extras/migrations/0044_add_job_hook.py +0 -1
- nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
- nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
- nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
- nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
- nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
- nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
- nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
- nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
- nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
- nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
- nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
- nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
- nautobot/extras/migrations/0057_jobbutton.py +0 -1
- nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
- nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
- nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
- nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
- nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
- nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
- nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
- nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
- nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
- nautobot/extras/migrations/0078_remove_slug.py +45 -0
- nautobot/extras/migrations/0079_tagsfield.py +28 -0
- nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
- nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
- nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
- nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
- nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
- nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
- nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
- nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
- nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
- nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
- nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
- nautobot/extras/models/__init__.py +2 -3
- nautobot/extras/models/change_logging.py +0 -36
- nautobot/extras/models/customfields.py +39 -33
- nautobot/extras/models/datasources.py +48 -50
- nautobot/extras/models/groups.py +5 -12
- nautobot/extras/models/jobs.py +190 -323
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +1 -22
- nautobot/extras/models/relationships.py +20 -21
- nautobot/extras/models/roles.py +0 -23
- nautobot/extras/models/secrets.py +2 -31
- nautobot/extras/models/statuses.py +6 -5
- nautobot/extras/models/tags.py +2 -17
- nautobot/extras/navigation.py +89 -307
- nautobot/extras/plugins/__init__.py +3 -121
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -4
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +42 -49
- nautobot/extras/tasks.py +0 -12
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +16 -1
- nautobot/extras/templates/extras/customfield.html +0 -13
- nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
- nautobot/extras/templates/extras/gitrepository.html +3 -3
- nautobot/extras/templates/extras/inc/jobresult.html +10 -0
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/job.html +35 -25
- nautobot/extras/templates/extras/job_approval_request.html +15 -30
- nautobot/extras/templates/extras/job_detail.html +13 -31
- nautobot/extras/templates/extras/job_edit.html +14 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/objectchange_list.html +1 -1
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templates/extras/secret_edit.html +0 -1
- nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
- nautobot/extras/templatetags/custom_links.py +0 -2
- nautobot/extras/templatetags/job_buttons.py +1 -0
- nautobot/extras/templatetags/plugins.py +0 -1
- nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
- nautobot/extras/test_jobs/atomic_transaction.py +53 -0
- nautobot/extras/test_jobs/dry_run.py +29 -0
- nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
- nautobot/extras/test_jobs/duplicate_name2.py +9 -0
- nautobot/extras/test_jobs/fail.py +23 -0
- nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
- nautobot/extras/test_jobs/file_upload_pass.py +25 -0
- nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
- nautobot/extras/test_jobs/job_button_receiver.py +28 -0
- nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
- nautobot/extras/test_jobs/job_variables.py +88 -0
- nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
- nautobot/extras/test_jobs/log_redaction.py +20 -0
- nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
- nautobot/extras/test_jobs/modify_db.py +25 -0
- nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
- nautobot/extras/test_jobs/object_var_optional.py +21 -0
- nautobot/extras/test_jobs/object_var_required.py +21 -0
- nautobot/extras/test_jobs/object_vars.py +26 -0
- nautobot/extras/test_jobs/pass.py +25 -0
- nautobot/extras/test_jobs/profiling.py +32 -0
- nautobot/extras/test_jobs/read_only_job.py +15 -0
- nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
- nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
- nautobot/extras/tests/integration/__init__.py +3 -3
- nautobot/extras/tests/integration/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_plugins.py +4 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +371 -381
- nautobot/extras/tests/test_changelog.py +17 -16
- nautobot/extras/tests/test_context_managers.py +5 -6
- nautobot/extras/tests/test_customfields.py +112 -73
- nautobot/extras/tests/test_datasources.py +191 -117
- nautobot/extras/tests/test_dynamicgroups.py +45 -68
- nautobot/extras/tests/test_filters.py +170 -130
- nautobot/extras/tests/test_forms.py +107 -109
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +271 -273
- nautobot/extras/tests/test_management.py +3 -6
- nautobot/extras/tests/test_migrations.py +5 -3
- nautobot/extras/tests/test_models.py +121 -173
- nautobot/extras/tests/test_notes.py +0 -1
- nautobot/extras/tests/test_plugins.py +55 -89
- nautobot/extras/tests/test_relationships.py +174 -130
- nautobot/extras/tests/test_tags.py +6 -12
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +223 -184
- nautobot/extras/tests/test_webhooks.py +16 -15
- nautobot/extras/urls.py +69 -69
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +81 -153
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +77 -164
- nautobot/ipam/api/urls.py +4 -1
- nautobot/ipam/api/views.py +28 -19
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/choices.py +5 -12
- nautobot/ipam/constants.py +1 -0
- nautobot/ipam/factory.py +41 -30
- nautobot/ipam/filters.py +58 -25
- nautobot/ipam/forms.py +82 -211
- nautobot/ipam/graphql/types.py +0 -9
- nautobot/ipam/lookups.py +13 -8
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
- nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
- nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
- nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
- nautobot/ipam/migrations/0005_auto_slug.py +0 -1
- nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
- nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
- nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
- nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
- nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
- nautobot/ipam/migrations/0013_delete_role.py +0 -1
- nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
- nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
- nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
- nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
- nautobot/ipam/migrations/0019_created_datetime.py +0 -1
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
- nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
- nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
- nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
- nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
- nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
- nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
- nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
- nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
- nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
- nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
- nautobot/ipam/models.py +579 -368
- nautobot/ipam/navigation.py +36 -159
- nautobot/ipam/querysets.py +117 -90
- nautobot/ipam/signals.py +89 -0
- nautobot/ipam/tables.py +86 -28
- nautobot/ipam/templates/ipam/ipaddress.html +14 -30
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
- nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
- nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
- nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +27 -33
- nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf.html +6 -4
- nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
- nautobot/ipam/tests/integration/test_prefixes.py +4 -27
- nautobot/ipam/tests/test_api.py +60 -61
- nautobot/ipam/tests/test_filters.py +187 -126
- nautobot/ipam/tests/test_forms.py +12 -6
- nautobot/ipam/tests/test_graphql.py +8 -6
- nautobot/ipam/tests/test_migrations.py +8 -13
- nautobot/ipam/tests/test_models.py +426 -274
- nautobot/ipam/tests/test_ordering.py +6 -3
- nautobot/ipam/tests/test_querysets.py +340 -96
- nautobot/ipam/tests/test_views.py +100 -55
- nautobot/ipam/urls.py +28 -5
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +237 -122
- nautobot/project-static/docs/404.html +1399 -166
- nautobot/project-static/docs/additional-features/caching.html +1416 -320
- nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
- nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
- nautobot/project-static/docs/additional-features/graphql.html +1389 -190
- nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
- nautobot/project-static/docs/additional-features/jobs.html +1677 -460
- nautobot/project-static/docs/additional-features/napalm.html +1389 -190
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
- nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
- nautobot/project-static/docs/administration/celery-queues.html +1389 -190
- nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
- nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
- nautobot/project-static/docs/administration/permissions.html +1389 -190
- nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
- nautobot/project-static/docs/apps/index.html +1389 -190
- nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
- nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
- nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
- nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
- nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
- nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
- nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
- nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
- nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
- nautobot/project-static/docs/configuration/index.html +1398 -199
- nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
- nautobot/project-static/docs/configuration/required-settings.html +1419 -287
- nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
- nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
- nautobot/project-static/docs/core-functionality/devices.html +1452 -249
- nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
- nautobot/project-static/docs/core-functionality/power.html +1448 -249
- nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
- nautobot/project-static/docs/core-functionality/services.html +1448 -249
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
- nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
- nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
- nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
- nautobot/project-static/docs/development/application-registry.html +1393 -214
- nautobot/project-static/docs/development/best-practices.html +1392 -192
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
- nautobot/project-static/docs/development/extending-models.html +1443 -257
- nautobot/project-static/docs/development/generic-views.html +1403 -174
- nautobot/project-static/docs/development/getting-started.html +1568 -262
- nautobot/project-static/docs/development/homepage.html +1389 -190
- nautobot/project-static/docs/development/index.html +1389 -190
- nautobot/project-static/docs/development/model-features.html +1389 -190
- nautobot/project-static/docs/development/natural-keys.html +1389 -190
- nautobot/project-static/docs/development/navigation-menu.html +1451 -330
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1392 -193
- nautobot/project-static/docs/development/role-internals.html +1402 -172
- nautobot/project-static/docs/development/style-guide.html +1399 -199
- nautobot/project-static/docs/development/templates.html +1391 -191
- nautobot/project-static/docs/development/testing.html +1389 -190
- nautobot/project-static/docs/development/user-preferences.html +1389 -190
- nautobot/project-static/docs/docker/index.html +1408 -206
- nautobot/project-static/docs/index.html +1397 -180
- nautobot/project-static/docs/installation/centos.html +1401 -170
- nautobot/project-static/docs/installation/external-authentication.html +1389 -190
- nautobot/project-static/docs/installation/http-server.html +1389 -190
- nautobot/project-static/docs/installation/index.html +1394 -191
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
- nautobot/project-static/docs/installation/nautobot.html +1390 -191
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
- nautobot/project-static/docs/installation/services.html +1389 -190
- nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/project-static/docs/installation/ubuntu.html +1401 -170
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
- nautobot/project-static/docs/installation/upgrading.html +1395 -192
- nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
- nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
- nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
- nautobot/project-static/docs/models/circuits/provider.html +1427 -174
- nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
- nautobot/project-static/docs/models/dcim/cable.html +1458 -174
- nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/device.html +1431 -174
- nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
- nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
- nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/interface.html +1427 -174
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
- nautobot/project-static/docs/models/dcim/location.html +1427 -174
- nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
- nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
- nautobot/project-static/docs/models/dcim/platform.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
- nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/rack.html +1427 -174
- nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
- nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
- nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/region.html +1401 -170
- nautobot/project-static/docs/models/dcim/site.html +1401 -170
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
- nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
- nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
- nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
- nautobot/project-static/docs/models/extras/customfield.html +1389 -190
- nautobot/project-static/docs/models/extras/customlink.html +1389 -190
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
- nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
- nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
- nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
- nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
- nautobot/project-static/docs/models/extras/job.html +1411 -157
- nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
- nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
- nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
- nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
- nautobot/project-static/docs/models/extras/note.html +1389 -190
- nautobot/project-static/docs/models/extras/relationship.html +1391 -192
- nautobot/project-static/docs/models/extras/role.html +1495 -198
- nautobot/project-static/docs/models/extras/secret.html +1492 -201
- nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
- nautobot/project-static/docs/models/extras/status.html +1381 -221
- nautobot/project-static/docs/models/extras/tag.html +1389 -190
- nautobot/project-static/docs/models/extras/webhook.html +1389 -190
- nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
- nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
- nautobot/project-static/docs/models/ipam/rir.html +1410 -157
- nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
- nautobot/project-static/docs/models/ipam/service.html +1410 -157
- nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
- nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
- nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
- nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
- nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
- nautobot/project-static/docs/models/users/token.html +1410 -157
- nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
- nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
- nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1916 -646
- nautobot/project-static/docs/plugins/index.html +1389 -190
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
- nautobot/project-static/docs/release-notes/index.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
- nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
- nautobot/project-static/docs/requirements.txt +5 -4
- nautobot/project-static/docs/rest-api/authentication.html +1389 -190
- nautobot/project-static/docs/rest-api/filtering.html +1389 -190
- nautobot/project-static/docs/rest-api/overview.html +2002 -576
- nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +197 -187
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
- nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
- nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
- nautobot/project-static/docs/user-guides/graphql.html +1402 -203
- nautobot/project-static/docs/user-guides/relationships.html +1448 -249
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -34
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/filters/__init__.py +9 -7
- nautobot/tenancy/filters/mixins.py +3 -2
- nautobot/tenancy/forms.py +3 -36
- nautobot/tenancy/migrations/0001_initial.py +0 -1
- nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
- nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
- nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
- nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
- nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -30
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/tables.py +4 -4
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -12
- nautobot/tenancy/tests/test_filters.py +20 -12
- nautobot/tenancy/tests/test_views.py +11 -29
- nautobot/tenancy/urls.py +10 -10
- nautobot/tenancy/views.py +0 -3
- nautobot/ui/.eslintignore +6 -0
- nautobot/ui/.gitignore +10 -0
- nautobot/ui/.prettierignore +9 -0
- nautobot/ui/.prettierrc +4 -0
- nautobot/ui/README.md +33 -0
- nautobot/ui/app_imports.js.j2 +7 -0
- nautobot/ui/craco.config.js +46 -0
- nautobot/ui/jsconfig-base.json +11 -0
- nautobot/ui/jsconfig.json +5 -0
- nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
- nautobot/ui/package-lock.json +21451 -0
- nautobot/ui/package.json +70 -0
- nautobot/ui/public/index.html +47 -0
- nautobot/ui/public/logo192.png +0 -0
- nautobot/ui/public/logo512.png +0 -0
- nautobot/ui/public/manifest.json +25 -0
- nautobot/ui/public/nautobot_logo.svg +131 -0
- nautobot/ui/public/robots.txt +3 -0
- nautobot/ui/src/App.js +71 -0
- nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
- nautobot/ui/src/components/AppTab.js +40 -0
- nautobot/ui/src/components/Apps.js +60 -0
- nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
- nautobot/ui/src/components/HomePanel.js +58 -0
- nautobot/ui/src/components/JobHistoryTable.js +78 -0
- nautobot/ui/src/components/Layout.js +53 -0
- nautobot/ui/src/components/LoadingWidget.js +25 -0
- nautobot/ui/src/components/Navbar.js +116 -0
- nautobot/ui/src/components/NotificationPopover.js +27 -0
- nautobot/ui/src/components/ObjectListTable.js +209 -0
- nautobot/ui/src/components/ReferenceDataTag.js +35 -0
- nautobot/ui/src/components/RouterButton.js +10 -0
- nautobot/ui/src/components/RouterLink.js +10 -0
- nautobot/ui/src/components/SidebarNav.js +147 -0
- nautobot/ui/src/components/Table.js +48 -0
- nautobot/ui/src/components/TableItem.js +71 -0
- nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
- nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
- nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
- nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
- nautobot/ui/src/components/__tests__/Table.test.js +36 -0
- nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
- nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
- nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
- nautobot/ui/src/components/pagination.js +93 -0
- nautobot/ui/src/components/paginator.js +79 -0
- nautobot/ui/src/components/paginator_form.js +43 -0
- nautobot/ui/src/components/usePagination.js +57 -0
- nautobot/ui/src/constants/apiPath.js +10 -0
- nautobot/ui/src/constants/icons.js +15 -0
- nautobot/ui/src/constants/size.js +15 -0
- nautobot/ui/src/index.js +65 -0
- nautobot/ui/src/reportWebVitals.js +15 -0
- nautobot/ui/src/router.js +77 -0
- nautobot/ui/src/utils/api.js +131 -0
- nautobot/ui/src/utils/app-import.js +15 -0
- nautobot/ui/src/utils/color.js +15 -0
- nautobot/ui/src/utils/date.js +14 -0
- nautobot/ui/src/utils/index.js +15 -0
- nautobot/ui/src/utils/navigation.js +32 -0
- nautobot/ui/src/utils/session.js +64 -0
- nautobot/ui/src/utils/store.js +242 -0
- nautobot/ui/src/utils/string.js +6 -0
- nautobot/ui/src/utils/url.js +4 -0
- nautobot/ui/src/views/Home.js +138 -0
- nautobot/ui/src/views/InstalledApps.js +80 -0
- nautobot/ui/src/views/Login.js +48 -0
- nautobot/ui/src/views/Logout.js +20 -0
- nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
- nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
- nautobot/ui/src/views/__tests__/Login.test.js +15 -0
- nautobot/ui/src/views/generic/GenericView.js +142 -0
- nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
- nautobot/ui/src/views/generic/ObjectList.js +127 -0
- nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +51 -61
- nautobot/users/api/urls.py +1 -1
- nautobot/users/api/views.py +53 -2
- nautobot/users/migrations/0001_initial.py +0 -1
- nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
- nautobot/users/migrations/0003_alter_user_options.py +0 -1
- nautobot/users/migrations/0004_alter_user_managers.py +0 -1
- nautobot/users/tests/test_api.py +109 -28
- nautobot/users/tests/test_filters.py +0 -4
- nautobot/users/tests/test_models.py +0 -1
- nautobot/users/views.py +0 -7
- nautobot/virtualization/api/serializers.py +18 -132
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/choices.py +0 -2
- nautobot/virtualization/filters.py +12 -7
- nautobot/virtualization/forms.py +21 -117
- nautobot/virtualization/migrations/0001_initial.py +0 -1
- nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
- nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
- nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
- nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
- nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
- nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
- nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
- nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
- nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
- nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
- nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
- nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
- nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
- nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
- nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
- nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
- nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
- nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +39 -131
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/tables.py +4 -4
- nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +42 -52
- nautobot/virtualization/tests/test_filters.py +98 -75
- nautobot/virtualization/tests/test_models.py +36 -13
- nautobot/virtualization/tests/test_views.py +68 -73
- nautobot/virtualization/urls.py +10 -10
- nautobot/virtualization/views.py +8 -14
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
- nautobot/circuits/api/nested_serializers.py +0 -69
- nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
- nautobot/dcim/api/nested_serializers.py +0 -356
- nautobot/dcim/templates/dcim/device_import.html +0 -5
- nautobot/dcim/templates/dcim/device_import_child.html +0 -5
- nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
- nautobot/extras/api/nested_serializers.py +0 -353
- nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
- nautobot/extras/reports.py +0 -60
- nautobot/extras/scripts.py +0 -72
- nautobot/extras/tests/example_jobs/script_variables.py +0 -67
- nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
- nautobot/extras/tests/example_jobs/test_fail.py +0 -16
- nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
- nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
- nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
- nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
- nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
- nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
- nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
- nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
- nautobot/extras/tests/example_jobs/test_pass.py +0 -19
- nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
- nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
- nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
- nautobot/ipam/api/nested_serializers.py +0 -143
- nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
- nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
- nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
- nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
- nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
- nautobot/tenancy/api/nested_serializers.py +0 -31
- nautobot/users/api/nested_serializers.py +0 -67
- nautobot/virtualization/api/nested_serializers.py +0 -65
- /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
- /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
nautobot/core/testing/mixins.py
CHANGED
|
@@ -9,8 +9,7 @@ from django.db.models import JSONField, ManyToManyField
|
|
|
9
9
|
from django.forms.models import model_to_dict
|
|
10
10
|
from django.utils.text import slugify
|
|
11
11
|
from netaddr import IPNetwork
|
|
12
|
-
from rest_framework.test import APIClient
|
|
13
|
-
from taggit.managers import TaggableManager
|
|
12
|
+
from rest_framework.test import APIClient, APIRequestFactory
|
|
14
13
|
|
|
15
14
|
from nautobot.core import testing
|
|
16
15
|
from nautobot.core.models import fields as core_fields
|
|
@@ -93,8 +92,7 @@ class NautobotTestCaseMixin:
|
|
|
93
92
|
field = None
|
|
94
93
|
|
|
95
94
|
# Handle ManyToManyFields
|
|
96
|
-
if value and isinstance(field, (ManyToManyField,
|
|
97
|
-
|
|
95
|
+
if value and isinstance(field, (ManyToManyField, core_fields.TagsField)):
|
|
98
96
|
# Only convert ContentType to <app_label>.<model> for API serializers/views
|
|
99
97
|
if api and field.related_model is ContentType:
|
|
100
98
|
model_dict[key] = sorted([f"{ct.app_label}.{ct.model}" for ct in value])
|
|
@@ -103,7 +101,6 @@ class NautobotTestCaseMixin:
|
|
|
103
101
|
model_dict[key] = sorted([obj.pk for obj in value])
|
|
104
102
|
|
|
105
103
|
if api:
|
|
106
|
-
|
|
107
104
|
# Replace ContentType primary keys with <app_label>.<model>
|
|
108
105
|
if isinstance(getattr(instance, key), ContentType):
|
|
109
106
|
ct = ContentType.objects.get(pk=value)
|
|
@@ -114,7 +111,6 @@ class NautobotTestCaseMixin:
|
|
|
114
111
|
model_dict[key] = str(value)
|
|
115
112
|
|
|
116
113
|
else:
|
|
117
|
-
|
|
118
114
|
# Convert ArrayFields to CSV strings
|
|
119
115
|
if isinstance(field, core_fields.JSONArrayField):
|
|
120
116
|
model_dict[key] = ",".join([str(v) for v in value])
|
|
@@ -153,14 +149,13 @@ class NautobotTestCaseMixin:
|
|
|
153
149
|
if isinstance(expected_status, int):
|
|
154
150
|
expected_status = [expected_status]
|
|
155
151
|
if response.status_code not in expected_status:
|
|
152
|
+
err_message = f"Expected HTTP status(es) {expected_status}; received {response.status_code}:"
|
|
156
153
|
if hasattr(response, "data"):
|
|
157
154
|
# REST API response; pass the response data through directly
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
err = form_errors or response.content.decode(response.charset) or "No data"
|
|
163
|
-
err_message = f"Expected HTTP status(es) {expected_status}; received {response.status_code}: {err}"
|
|
155
|
+
err_message += f"\n{response.data}"
|
|
156
|
+
# Attempt to extract form validation errors from the response HTML
|
|
157
|
+
form_errors = testing.extract_form_failures(response.content.decode(response.charset))
|
|
158
|
+
err_message += "\n" + str(form_errors or response.content.decode(response.charset) or "No data")
|
|
164
159
|
if msg:
|
|
165
160
|
err_message = f"{msg}\n{err_message}"
|
|
166
161
|
self.assertIn(response.status_code, expected_status, err_message)
|
|
@@ -186,6 +181,9 @@ class NautobotTestCaseMixin:
|
|
|
186
181
|
if isinstance(v, list):
|
|
187
182
|
# Sort lists of values. This includes items like tags, or other M2M fields
|
|
188
183
|
new_model_dict[k] = sorted(v)
|
|
184
|
+
elif k == "data_schema" and isinstance(v, str):
|
|
185
|
+
# Standardize the data_schema JSON, since the column is JSON and MySQL/dolt do not guarantee order
|
|
186
|
+
new_model_dict[k] = self.standardize_json(v)
|
|
189
187
|
else:
|
|
190
188
|
new_model_dict[k] = v
|
|
191
189
|
|
|
@@ -196,6 +194,9 @@ class NautobotTestCaseMixin:
|
|
|
196
194
|
if isinstance(v, list):
|
|
197
195
|
# Sort lists of values. This includes items like tags, or other M2M fields
|
|
198
196
|
relevant_data[k] = sorted(v)
|
|
197
|
+
elif k == "data_schema" and isinstance(v, str):
|
|
198
|
+
# Standardize the data_schema JSON, since the column is JSON and MySQL/dolt do not guarantee order
|
|
199
|
+
relevant_data[k] = self.standardize_json(v)
|
|
199
200
|
else:
|
|
200
201
|
relevant_data[k] = v
|
|
201
202
|
|
|
@@ -213,6 +214,15 @@ class NautobotTestCaseMixin:
|
|
|
213
214
|
# Convenience methods
|
|
214
215
|
#
|
|
215
216
|
|
|
217
|
+
def absolute_api_url(self, obj):
|
|
218
|
+
"""Get the absolute API URL ("http://nautobot.example.com/api/...") for a given object."""
|
|
219
|
+
request = APIRequestFactory(SERVER_NAME="nautobot.example.com").get("")
|
|
220
|
+
return request.build_absolute_uri(obj.get_absolute_url(api=True))
|
|
221
|
+
|
|
222
|
+
def standardize_json(self, data):
|
|
223
|
+
obj = json.loads(data)
|
|
224
|
+
return json.dumps(obj, sort_keys=True)
|
|
225
|
+
|
|
216
226
|
@classmethod
|
|
217
227
|
def create_tags(cls, *names):
|
|
218
228
|
"""
|
nautobot/core/testing/schema.py
CHANGED
|
@@ -4,6 +4,7 @@ import yaml
|
|
|
4
4
|
from django.conf import settings
|
|
5
5
|
from django.core.management import call_command
|
|
6
6
|
from django.test import tag
|
|
7
|
+
from rest_framework.settings import api_settings
|
|
7
8
|
|
|
8
9
|
from nautobot.core.testing import views
|
|
9
10
|
|
|
@@ -18,7 +19,7 @@ class OpenAPISchemaTestCases:
|
|
|
18
19
|
# We could load the schema from the /api/swagger.yaml endpoint in setUp(self) via self.client,
|
|
19
20
|
# but it's fairly expensive to do so. Better to do so only once per class.
|
|
20
21
|
cls.schemas = {}
|
|
21
|
-
for api_version in
|
|
22
|
+
for api_version in api_settings.ALLOWED_VERSIONS:
|
|
22
23
|
out = StringIO()
|
|
23
24
|
err = StringIO()
|
|
24
25
|
call_command("spectacular", "--api-version", api_version, stdout=out, stderr=err)
|
nautobot/core/testing/views.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import csv
|
|
2
1
|
import re
|
|
3
|
-
from io import StringIO
|
|
4
2
|
from typing import Optional, Sequence
|
|
5
3
|
from unittest import skipIf
|
|
6
4
|
import uuid
|
|
@@ -13,11 +11,11 @@ from django.test import TestCase as _TestCase
|
|
|
13
11
|
from django.test import override_settings, tag
|
|
14
12
|
from django.urls import NoReverseMatch, reverse
|
|
15
13
|
from django.utils.http import urlencode
|
|
14
|
+
from django.utils.html import escape
|
|
16
15
|
from django.utils.text import slugify
|
|
17
16
|
from tree_queries.models import TreeNode
|
|
18
17
|
|
|
19
18
|
from nautobot.core import testing
|
|
20
|
-
from nautobot.core.views import utils as view_utils
|
|
21
19
|
from nautobot.core.templatetags import helpers
|
|
22
20
|
from nautobot.core.testing import mixins
|
|
23
21
|
from nautobot.core.utils import lookup
|
|
@@ -174,7 +172,7 @@ class ViewTestCases:
|
|
|
174
172
|
response_body = testing.extract_page_body(response.content.decode(response.charset))
|
|
175
173
|
|
|
176
174
|
# The object's display name or string representation should appear in the response
|
|
177
|
-
self.assertIn(getattr(instance, "display", str(instance)), response_body, msg=response_body)
|
|
175
|
+
self.assertIn(escape(getattr(instance, "display", str(instance))), response_body, msg=response_body)
|
|
178
176
|
|
|
179
177
|
# If any Relationships are defined, they should appear in the response
|
|
180
178
|
if self.relationships is not None:
|
|
@@ -182,13 +180,13 @@ class ViewTestCases:
|
|
|
182
180
|
content_type = ContentType.objects.get_for_model(instance)
|
|
183
181
|
if content_type == relationship.source_type:
|
|
184
182
|
self.assertIn(
|
|
185
|
-
relationship.get_label(extras_choices.RelationshipSideChoices.SIDE_SOURCE),
|
|
183
|
+
escape(relationship.get_label(extras_choices.RelationshipSideChoices.SIDE_SOURCE)),
|
|
186
184
|
response_body,
|
|
187
185
|
msg=response_body,
|
|
188
186
|
)
|
|
189
187
|
if content_type == relationship.destination_type:
|
|
190
188
|
self.assertIn(
|
|
191
|
-
relationship.get_label(extras_choices.RelationshipSideChoices.SIDE_DESTINATION),
|
|
189
|
+
escape(relationship.get_label(extras_choices.RelationshipSideChoices.SIDE_DESTINATION)),
|
|
192
190
|
response_body,
|
|
193
191
|
msg=response_body,
|
|
194
192
|
)
|
|
@@ -196,12 +194,14 @@ class ViewTestCases:
|
|
|
196
194
|
# If any Custom Fields are defined, they should appear in the response
|
|
197
195
|
if self.custom_fields is not None:
|
|
198
196
|
for custom_field in self.custom_fields: # false positive pylint: disable=not-an-iterable
|
|
199
|
-
self.assertIn(str(custom_field), response_body, msg=response_body)
|
|
197
|
+
self.assertIn(escape(str(custom_field)), response_body, msg=response_body)
|
|
200
198
|
if custom_field.type == extras_choices.CustomFieldTypeChoices.TYPE_MULTISELECT:
|
|
201
199
|
for value in instance.cf.get(custom_field.key):
|
|
202
|
-
self.assertIn(str(value), response_body, msg=response_body)
|
|
200
|
+
self.assertIn(escape(str(value)), response_body, msg=response_body)
|
|
203
201
|
else:
|
|
204
|
-
self.assertIn(
|
|
202
|
+
self.assertIn(
|
|
203
|
+
escape(str(instance.cf.get(custom_field.key) or "")), response_body, msg=response_body
|
|
204
|
+
)
|
|
205
205
|
|
|
206
206
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
207
207
|
def test_get_object_with_constrained_permission(self):
|
|
@@ -312,9 +312,10 @@ class ViewTestCases:
|
|
|
312
312
|
self.assertHttpStatus(self.client.post(**request), 302)
|
|
313
313
|
self.assertEqual(initial_count + 1, self._get_queryset().count())
|
|
314
314
|
# order_by() is no supported by django TreeNode,
|
|
315
|
-
# So we directly retrieve the instance by "slug".
|
|
315
|
+
# So we directly retrieve the instance by "slug" or "name".
|
|
316
316
|
if isinstance(self._get_queryset().first(), TreeNode):
|
|
317
|
-
|
|
317
|
+
filter_by = self.slug_source if getattr(self, "slug_source", None) else "name"
|
|
318
|
+
instance = self._get_queryset().get(**{filter_by: self.form_data.get(filter_by)})
|
|
318
319
|
self.assertInstanceEqual(instance, self.form_data)
|
|
319
320
|
else:
|
|
320
321
|
if hasattr(self.model, "last_updated"):
|
|
@@ -369,7 +370,8 @@ class ViewTestCases:
|
|
|
369
370
|
# order_by() is no supported by django TreeNode,
|
|
370
371
|
# So we directly retrieve the instance by "slug".
|
|
371
372
|
if isinstance(self._get_queryset().first(), TreeNode):
|
|
372
|
-
|
|
373
|
+
filter_by = self.slug_source if getattr(self, "slug_source", None) else "name"
|
|
374
|
+
instance = self._get_queryset().get(**{filter_by: self.form_data.get(filter_by)})
|
|
373
375
|
self.assertInstanceEqual(instance, self.form_data)
|
|
374
376
|
else:
|
|
375
377
|
if hasattr(self.model, "last_updated"):
|
|
@@ -380,7 +382,7 @@ class ViewTestCases:
|
|
|
380
382
|
def test_slug_autocreation(self):
|
|
381
383
|
"""Test that slug is autocreated through ORM."""
|
|
382
384
|
# This really should go on a models test page, but we don't have test structures for models.
|
|
383
|
-
if self.slug_source is not None:
|
|
385
|
+
if getattr(self.model, "slug_source", None) is not None:
|
|
384
386
|
obj = self.model.objects.get(**{self.slug_source: self.slug_test_object})
|
|
385
387
|
expected_slug = self.slugify_function(getattr(obj, self.slug_source))
|
|
386
388
|
self.assertEqual(obj.slug, expected_slug)
|
|
@@ -388,7 +390,7 @@ class ViewTestCases:
|
|
|
388
390
|
def test_slug_not_modified(self):
|
|
389
391
|
"""Ensure save method does not modify slug that is passed in."""
|
|
390
392
|
# This really should go on a models test page, but we don't have test structures for models.
|
|
391
|
-
if self.slug_source is not None:
|
|
393
|
+
if getattr(self.model, "slug_source", None) is not None:
|
|
392
394
|
new_slug_source_value = "kwyjibo"
|
|
393
395
|
|
|
394
396
|
obj = self.model.objects.get(**{self.slug_source: self.slug_test_object})
|
|
@@ -654,8 +656,8 @@ class ViewTestCases:
|
|
|
654
656
|
content = testing.extract_page_body(response.content.decode(response.charset))
|
|
655
657
|
# TODO: it'd make test failures more readable if we strip the page headers/footers from the content
|
|
656
658
|
if hasattr(self.model, "name"):
|
|
657
|
-
self.assertRegex(content, r">\s*" + re.escape(instance1.name) + r"\s*<", msg=content)
|
|
658
|
-
self.assertNotRegex(content, r">\s*" + re.escape(instance2.name) + r"\s*<", msg=content)
|
|
659
|
+
self.assertRegex(content, r">\s*" + re.escape(escape(instance1.name)) + r"\s*<", msg=content)
|
|
660
|
+
self.assertNotRegex(content, r">\s*" + re.escape(escape(instance2.name)) + r"\s*<", msg=content)
|
|
659
661
|
try:
|
|
660
662
|
self.assertIn(self._get_url("view", instance=instance1), content, msg=content)
|
|
661
663
|
self.assertNotIn(self._get_url("view", instance=instance2), content, msg=content)
|
|
@@ -788,39 +790,6 @@ class ViewTestCases:
|
|
|
788
790
|
f"<div>You are viewing a table of {self.model._meta.verbose_name_plural}</div>", response_body
|
|
789
791
|
)
|
|
790
792
|
|
|
791
|
-
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
792
|
-
def test_queryset_to_csv(self):
|
|
793
|
-
# Built-in CSV export
|
|
794
|
-
if not hasattr(self.model, "csv_headers"):
|
|
795
|
-
self.skipTest(f"{self.model} has no csv_headers attribute?")
|
|
796
|
-
response = self.client.get(f"{self._get_url('list')}?export")
|
|
797
|
-
self.assertHttpStatus(response, 200)
|
|
798
|
-
self.assertEqual(response.get("Content-Type"), "text/csv")
|
|
799
|
-
instance1 = self._get_queryset().first()
|
|
800
|
-
# With filtering
|
|
801
|
-
response = self.client.get(f"{self._get_url('list')}?export&id={instance1.pk}")
|
|
802
|
-
self.assertHttpStatus(response, 200)
|
|
803
|
-
self.assertEqual(response.get("Content-Type"), "text/csv")
|
|
804
|
-
response_body = response.content.decode(response.charset)
|
|
805
|
-
reader = csv.DictReader(StringIO(response_body))
|
|
806
|
-
# This line will make data a dictionary with csv headers as keys and corresponding csv values as values.
|
|
807
|
-
# For example:
|
|
808
|
-
# {'name': 'AFRINIC', 'slug': 'afrinic', 'is_private': '', 'description': ...'}
|
|
809
|
-
data = [dict(row) for row in reader][0]
|
|
810
|
-
|
|
811
|
-
# Get expected data
|
|
812
|
-
instance1_unformatted_data = [
|
|
813
|
-
*instance1.to_csv(),
|
|
814
|
-
*instance1.get_custom_fields().values(),
|
|
815
|
-
]
|
|
816
|
-
# Format expected data using `csv_format`, parse back with `csv` and get first row
|
|
817
|
-
instance1_csv_data = next(iter(csv.reader([view_utils.csv_format(instance1_unformatted_data)])))
|
|
818
|
-
|
|
819
|
-
instance1_cf_headers = [cf.add_prefix_to_cf_key() for cf in instance1.get_custom_fields().keys()]
|
|
820
|
-
instance1_csv_headers = list(self.model.csv_headers) + instance1_cf_headers
|
|
821
|
-
self.assertEqual(instance1_csv_headers, list(data.keys()))
|
|
822
|
-
self.assertEqual(instance1_csv_data, list(data.values()))
|
|
823
|
-
|
|
824
793
|
class CreateMultipleObjectsViewTestCase(ModelViewTestCase):
|
|
825
794
|
"""
|
|
826
795
|
Create multiple instances using a single form. Expects the creation of three new instances by default.
|
|
@@ -916,6 +885,9 @@ class ViewTestCases:
|
|
|
916
885
|
"""
|
|
917
886
|
Create multiple instances from imported data.
|
|
918
887
|
|
|
888
|
+
Note that CSV import, since it's now implemented via the REST API,
|
|
889
|
+
is also exercised by APIViewTestCases.CreateObjectViewTestCase.test_recreate_object_csv().
|
|
890
|
+
|
|
919
891
|
:csv_data: A list of CSV-formatted lines (starting with the headers) to be used for bulk object import.
|
|
920
892
|
"""
|
|
921
893
|
|
|
@@ -977,8 +949,13 @@ class ViewTestCases:
|
|
|
977
949
|
self.assertHttpStatus(self.client.get(self._get_url("import")), 200)
|
|
978
950
|
|
|
979
951
|
# Test POST with permission
|
|
980
|
-
self.
|
|
981
|
-
self.
|
|
952
|
+
response = self.client.post(self._get_url("import"), data)
|
|
953
|
+
self.assertHttpStatus(response, 200)
|
|
954
|
+
self.assertEqual(
|
|
955
|
+
self._get_queryset().count(),
|
|
956
|
+
initial_count + len(self.csv_data) - 1,
|
|
957
|
+
testing.extract_page_body(response.content.decode(response.charset)),
|
|
958
|
+
)
|
|
982
959
|
|
|
983
960
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
984
961
|
def test_bulk_import_objects_with_constrained_permission(self):
|
|
@@ -5,7 +5,7 @@ from nautobot.core.testing.integration import SeleniumTestCase
|
|
|
5
5
|
from nautobot.dcim.factory import LocationTypeFactory
|
|
6
6
|
from nautobot.dcim.models import Location, LocationType
|
|
7
7
|
from nautobot.extras.choices import CustomFieldTypeChoices
|
|
8
|
-
from nautobot.extras.models import CustomField, CustomFieldChoice
|
|
8
|
+
from nautobot.extras.models import CustomField, CustomFieldChoice, Status
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class ListViewFilterTestCase(SeleniumTestCase):
|
|
@@ -22,11 +22,18 @@ class ListViewFilterTestCase(SeleniumTestCase):
|
|
|
22
22
|
lt2 = LocationType.objects.get(name="Root")
|
|
23
23
|
lt3 = LocationType.objects.get(name="Building")
|
|
24
24
|
lt4 = LocationType.objects.get(name="Floor")
|
|
25
|
-
|
|
26
|
-
Location.objects.create(name="Filter Test Location
|
|
27
|
-
|
|
28
|
-
Location.objects.create(
|
|
29
|
-
|
|
25
|
+
location_status = Status.objects.get_for_model(Location).first()
|
|
26
|
+
campus_loc = Location.objects.create(name="Filter Test Location 1", location_type=lt1, status=location_status)
|
|
27
|
+
Location.objects.create(name="Filter Test Location 2", location_type=lt2, status=location_status)
|
|
28
|
+
building_loc = Location.objects.create(
|
|
29
|
+
name="Filter Test Location 3", location_type=lt3, parent=campus_loc, status=location_status
|
|
30
|
+
)
|
|
31
|
+
Location.objects.create(
|
|
32
|
+
name="Filter Test Location 4", location_type=lt4, parent=building_loc, status=location_status
|
|
33
|
+
)
|
|
34
|
+
Location.objects.create(
|
|
35
|
+
name="Filter Test Location 5", location_type=lt4, parent=building_loc, status=location_status
|
|
36
|
+
)
|
|
30
37
|
# set test user to admin
|
|
31
38
|
self.user.is_superuser = True
|
|
32
39
|
self.user.save()
|
|
@@ -102,7 +109,8 @@ class ListViewFilterTestCase(SeleniumTestCase):
|
|
|
102
109
|
# navigate back to the filter page and try the individual filter remove X button
|
|
103
110
|
self.browser.visit(filtered_locations_url)
|
|
104
111
|
remove_single_filter = self.browser.find_by_xpath(
|
|
105
|
-
"//div[@class='filters-applied']//span[@class='filter-selection']//
|
|
112
|
+
"//div[@class='filters-applied']//span[@class='filter-selection']//"
|
|
113
|
+
"span[@class='filter-selection-choice-remove remove-filter-param']",
|
|
106
114
|
wait_time=10,
|
|
107
115
|
)
|
|
108
116
|
remove_single_filter.click()
|
|
@@ -121,7 +129,8 @@ class ListViewFilterTestCase(SeleniumTestCase):
|
|
|
121
129
|
value (str or int): The value to fill in the input field or select from the select field.
|
|
122
130
|
field_type (str, optional): The type of the field, either "input" or "select".
|
|
123
131
|
idx (int, optional): The index of the field in case there are multiple fields with the same name.
|
|
124
|
-
select2_field_name (str, optional): The name of the select2 field in case it is different from the
|
|
132
|
+
select2_field_name (str, optional): The name of the select2 field in case it is different from the
|
|
133
|
+
input field name.
|
|
125
134
|
"""
|
|
126
135
|
if field_type == "input":
|
|
127
136
|
self.browser.find_by_name(field_name)[idx].fill(value)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from django.test.utils import override_settings
|
|
2
2
|
|
|
3
|
-
from nautobot.core.choices import ButtonActionColorChoices, ButtonActionIconChoices
|
|
4
3
|
from nautobot.core.testing.integration import SeleniumTestCase
|
|
5
4
|
|
|
6
5
|
|
|
@@ -9,30 +8,22 @@ class NavBarTestCase(SeleniumTestCase):
|
|
|
9
8
|
|
|
10
9
|
fixtures = ["user-data.json"]
|
|
11
10
|
navbar = {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
11
|
+
"Inventory": {
|
|
12
|
+
"Organization": {
|
|
14
13
|
"Locations": {
|
|
15
14
|
"permission": "dcim.view_location",
|
|
16
|
-
"buttons": ["Add", "Import"],
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
"Tags": {
|
|
20
|
-
"Tags": {
|
|
21
|
-
"permission": "extras.view_tag",
|
|
22
|
-
"buttons": ["Add", "Import"],
|
|
23
15
|
},
|
|
24
16
|
},
|
|
25
17
|
},
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"Add",
|
|
32
|
-
],
|
|
18
|
+
# don't use "Networks" here as the underspecified xpaths below will be fooled by DCIM "Provider Networks"
|
|
19
|
+
"Automation": {
|
|
20
|
+
"Extensibility": {
|
|
21
|
+
"Webhooks": {
|
|
22
|
+
"permission": "extras.view_webhook",
|
|
33
23
|
},
|
|
34
24
|
},
|
|
35
25
|
},
|
|
26
|
+
# don't use "Platform" here as the underspecified xpaths below will be fooled by DCIM "Platforms"
|
|
36
27
|
}
|
|
37
28
|
|
|
38
29
|
def setUp(self):
|
|
@@ -66,23 +57,9 @@ class NavBarTestCase(SeleniumTestCase):
|
|
|
66
57
|
# Append onto tab xpath with group name search
|
|
67
58
|
group = tab.find_by_xpath(f"{tab_xpath}/following-sibling::ul//li[contains(text(), '{group_name}')]")
|
|
68
59
|
|
|
69
|
-
for item_name
|
|
60
|
+
for item_name in items:
|
|
70
61
|
item_xpath = f"{tab_xpath}/following-sibling::ul//li[.//a[contains(text(), '{item_name}')]]"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for button_name in item_details["buttons"]:
|
|
74
|
-
button = item.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']")
|
|
75
|
-
# Ensure button has matching class for its name
|
|
76
|
-
button_class = getattr(ButtonActionColorChoices, button_name.upper(), None)
|
|
77
|
-
if button_class:
|
|
78
|
-
rendered_button_class = button["class"].split(" ")[-1].split("-")[-1]
|
|
79
|
-
self.assertEqual(button_class, rendered_button_class)
|
|
80
|
-
# Ensure button has matching icon for its name
|
|
81
|
-
button_icon = getattr(ButtonActionIconChoices, button_name.upper(), None)
|
|
82
|
-
if button_icon:
|
|
83
|
-
icon = button.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']/i")
|
|
84
|
-
rendered_button_icon = icon["class"].split(" ")[-1]
|
|
85
|
-
self.assertEqual(button_icon, rendered_button_icon)
|
|
62
|
+
group.find_by_xpath(item_xpath)
|
|
86
63
|
|
|
87
64
|
@override_settings(HIDE_RESTRICTED_UI=False)
|
|
88
65
|
def test_navbar_render_limit_permissions(self):
|
|
@@ -132,7 +109,7 @@ class NavBarTestCase(SeleniumTestCase):
|
|
|
132
109
|
# Append onto tab xpath with group name search
|
|
133
110
|
group = tab.find_by_xpath(f"{tab_xpath}/following-sibling::ul//li[contains(text(), '{group_name}')]")
|
|
134
111
|
|
|
135
|
-
for item_name
|
|
112
|
+
for item_name in items:
|
|
136
113
|
item_xpath = f"{tab_xpath}/following-sibling::ul//li[.//a[contains(text(), '{item_name}')]]"
|
|
137
114
|
item = group.find_by_xpath(item_xpath)
|
|
138
115
|
self.assertEqual(item["class"], "disabled", f"Item `{item_name}` should be disabled.")
|
|
@@ -2,7 +2,6 @@ from unittest import skipIf
|
|
|
2
2
|
|
|
3
3
|
from django.conf import settings
|
|
4
4
|
|
|
5
|
-
from nautobot.core.choices import ButtonActionColorChoices, ButtonActionIconChoices
|
|
6
5
|
from nautobot.core.testing.integration import SeleniumTestCase
|
|
7
6
|
|
|
8
7
|
|
|
@@ -15,47 +14,21 @@ class PluginNavBarTestCase(SeleniumTestCase):
|
|
|
15
14
|
|
|
16
15
|
fixtures = ["user-data.json"]
|
|
17
16
|
navbar = {
|
|
18
|
-
"
|
|
19
|
-
"Example
|
|
17
|
+
"Inventory": {
|
|
18
|
+
"Example App": {
|
|
20
19
|
"Example Model": {
|
|
21
20
|
"permission": "example_plugin.view_examplemodel",
|
|
22
|
-
"buttons": ["Add", "Import"],
|
|
23
21
|
},
|
|
24
22
|
},
|
|
25
|
-
},
|
|
26
|
-
"Circuits": {
|
|
27
23
|
"Circuits": {
|
|
28
24
|
"Circuits": {
|
|
29
25
|
"permission": "circuits.view_circuit",
|
|
30
|
-
"buttons": ["Add", "Import"],
|
|
31
26
|
},
|
|
32
|
-
"Circuit
|
|
27
|
+
"Circuit Types": {
|
|
33
28
|
"permission": "circuits.view_circuittype",
|
|
34
|
-
"buttons": ["Add", "Import"],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
"Example Circuit Group": {
|
|
38
|
-
"Example Model": {
|
|
39
|
-
"permission": "example_plugin.view_examplemodel",
|
|
40
|
-
"buttons": ["Add", "Import"],
|
|
41
29
|
},
|
|
42
|
-
},
|
|
43
|
-
"Providers": {
|
|
44
30
|
"Providers": {
|
|
45
31
|
"permission": "circuits.view_provider",
|
|
46
|
-
"buttons": ["Add", "Import"],
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
"Plugins": {
|
|
51
|
-
"Example Nautobot App": {
|
|
52
|
-
"Models": {
|
|
53
|
-
"permission": "example_plugin.view_examplemodel",
|
|
54
|
-
"buttons": ["Add a new example model", "Import example models"],
|
|
55
|
-
},
|
|
56
|
-
"Other Models": {
|
|
57
|
-
"permission": "example_plugin.view_examplemodel",
|
|
58
|
-
"buttons": [],
|
|
59
32
|
},
|
|
60
33
|
},
|
|
61
34
|
},
|
|
@@ -69,9 +42,9 @@ class PluginNavBarTestCase(SeleniumTestCase):
|
|
|
69
42
|
self.logout()
|
|
70
43
|
super().tearDown()
|
|
71
44
|
|
|
72
|
-
def
|
|
45
|
+
def test_plugin_navbar_modify_context(self):
|
|
73
46
|
"""
|
|
74
|
-
Verify that
|
|
47
|
+
Verify that the example plugin is able to add a new group and items to an existing menu tab/context.
|
|
75
48
|
"""
|
|
76
49
|
# Set test user to admin
|
|
77
50
|
self.user.is_superuser = True
|
|
@@ -80,80 +53,13 @@ class PluginNavBarTestCase(SeleniumTestCase):
|
|
|
80
53
|
# Retrieve home page
|
|
81
54
|
self.browser.visit(self.live_server_url)
|
|
82
55
|
|
|
83
|
-
tab_xpath = "//*[@id='navbar']//*[contains(text(), '
|
|
56
|
+
tab_xpath = "//*[@id='navbar']//*[contains(text(), 'Inventory')]"
|
|
84
57
|
tab = self.browser.find_by_xpath(tab_xpath)
|
|
85
58
|
tab.click()
|
|
86
59
|
self.assertTrue(bool(tab["aria-expanded"]))
|
|
87
60
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
item_xpath = f"{tab_xpath}/following-sibling::ul//li[.//a[contains(text(), 'Example Model')]]"
|
|
91
|
-
group.find_by_xpath(item_xpath)
|
|
92
|
-
|
|
93
|
-
def test_plugin_navbar_modify_circuits(self):
|
|
94
|
-
"""
|
|
95
|
-
Verify that the example plugin is able to add a new group and items to an existing menu tab.
|
|
96
|
-
"""
|
|
97
|
-
# Set test user to admin
|
|
98
|
-
self.user.is_superuser = True
|
|
99
|
-
self.user.save()
|
|
100
|
-
|
|
101
|
-
# Retrieve home page
|
|
102
|
-
self.browser.visit(self.live_server_url)
|
|
103
|
-
|
|
104
|
-
tab_xpath = "//*[@id='navbar']//*[contains(text(), 'Circuits')]"
|
|
105
|
-
tab = self.browser.find_by_xpath(tab_xpath)
|
|
106
|
-
tab.click()
|
|
107
|
-
self.assertTrue(bool(tab["aria-expanded"]))
|
|
108
|
-
|
|
109
|
-
for group_name, items in self.navbar["Circuits"].items():
|
|
110
|
-
group = tab.find_by_xpath(f"{tab_xpath}/following-sibling::ul//li[contains(text(), '{group_name}')]")
|
|
111
|
-
for item_name, item_details in items.items():
|
|
112
|
-
item_xpath = f"{tab_xpath}/following-sibling::ul//li[.//a[contains(text(), '{item_name}')]]"
|
|
113
|
-
item = group.find_by_xpath(item_xpath)
|
|
114
|
-
|
|
115
|
-
for button_name in item_details["buttons"]:
|
|
116
|
-
button = item.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']")
|
|
117
|
-
# Ensure button has matching class for its name
|
|
118
|
-
button_class = getattr(ButtonActionColorChoices, button_name.upper(), None)
|
|
119
|
-
if button_class:
|
|
120
|
-
self.assertIn(button_class, button["class"])
|
|
121
|
-
# Ensure button has matching icon for its name
|
|
122
|
-
button_icon = getattr(ButtonActionIconChoices, button_name.upper(), None)
|
|
123
|
-
if button_icon:
|
|
124
|
-
icon = button.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']/i")
|
|
125
|
-
self.assertIn(button_icon, icon["class"])
|
|
126
|
-
|
|
127
|
-
def test_plugin_navbar_plugin_tab(self):
|
|
128
|
-
"""
|
|
129
|
-
Test that old-style plugin menu definitions are correctly rendered to the Plugins menu tab.
|
|
130
|
-
"""
|
|
131
|
-
# Set test user to admin
|
|
132
|
-
self.user.is_superuser = True
|
|
133
|
-
self.user.save()
|
|
134
|
-
|
|
135
|
-
# Retrieve home page
|
|
136
|
-
self.browser.visit(self.live_server_url)
|
|
137
|
-
|
|
138
|
-
tab_xpath = "//*[@id='navbar']//*[contains(text(), 'Plugins')]"
|
|
139
|
-
tab = self.browser.find_by_xpath(tab_xpath)
|
|
140
|
-
tab.click()
|
|
141
|
-
self.assertTrue(bool(tab["aria-expanded"]))
|
|
142
|
-
|
|
143
|
-
for group_name, items in self.navbar["Plugins"].items():
|
|
61
|
+
for group_name, items in self.navbar["Inventory"].items():
|
|
144
62
|
group = tab.find_by_xpath(f"{tab_xpath}/following-sibling::ul//li[contains(text(), '{group_name}')]")
|
|
145
|
-
for item_name
|
|
63
|
+
for item_name in items:
|
|
146
64
|
item_xpath = f"{tab_xpath}/following-sibling::ul//li[.//a[contains(text(), '{item_name}')]]"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
for button_name in item_details["buttons"]:
|
|
150
|
-
button = item.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']")
|
|
151
|
-
# Ensure button has matching class for its name
|
|
152
|
-
button_class = getattr(ButtonActionColorChoices, button_name.upper(), None)
|
|
153
|
-
if button_class:
|
|
154
|
-
self.assertIn(button_class, button.get_attribute("class"))
|
|
155
|
-
# Ensure button has matching icon for its name
|
|
156
|
-
button_icon = getattr(ButtonActionIconChoices, button_name.upper(), None)
|
|
157
|
-
if button_icon:
|
|
158
|
-
icon = button.find_by_xpath(f"{item_xpath}/div//a[@title='{button_name}']/i")
|
|
159
|
-
self.assertIn(button_icon, icon["class"])
|
|
65
|
+
group.find_by_xpath(item_xpath)
|
|
@@ -12,7 +12,7 @@ ALLOWED_HOSTS = ["nautobot.example.com"]
|
|
|
12
12
|
|
|
13
13
|
# Discover test jobs from within the Nautobot source code
|
|
14
14
|
JOBS_ROOT = os.path.join(
|
|
15
|
-
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "extras", "
|
|
15
|
+
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "extras", "test_jobs"
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
# Enable both example plugins
|
|
@@ -28,8 +28,6 @@ SECRET_KEY = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
|
28
28
|
|
|
29
29
|
# Use *different* redis_databases than the ones (0 and 1) used during non-automated-testing operations.
|
|
30
30
|
CACHES["default"]["LOCATION"] = parse_redis_connection(redis_database=2) # noqa: F405
|
|
31
|
-
CACHEOPS_REDIS = parse_redis_connection(redis_database=3)
|
|
32
|
-
CACHEOPS_ENABLED = False # 2.0 TODO(jathan): Remove me.
|
|
33
31
|
|
|
34
32
|
# Testing storages within cli.py
|
|
35
33
|
STORAGE_CONFIG = {
|
|
@@ -48,6 +46,7 @@ TEST_FACTORY_SEED = "Nautobot"
|
|
|
48
46
|
TEST_PERFORMANCE_BASELINE_FILE = "nautobot/core/tests/performance_baselines.yml"
|
|
49
47
|
|
|
50
48
|
# Make Celery run synchronously (eager), to always store eager results, and run the broker in-memory.
|
|
49
|
+
# NOTE: Celery does not honor the TASK_TRACK_STARTED config when running in eager mode, so the job result is not saved until after the task completes.
|
|
51
50
|
CELERY_TASK_ALWAYS_EAGER = True
|
|
52
51
|
CELERY_TASK_STORE_EAGER_RESULT = True
|
|
53
52
|
CELERY_BROKER_URL = "memory://"
|
nautobot/core/tests/runner.py
CHANGED